omkarenator commited on
Commit
b8cdbfb
0 Parent(s):

Initial commit

Browse files
.gitattributes ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ *.7z filter=lfs diff=lfs merge=lfs -text
2
+ *.arrow filter=lfs diff=lfs merge=lfs -text
3
+ *.bin filter=lfs diff=lfs merge=lfs -text
4
+ *.bz2 filter=lfs diff=lfs merge=lfs -text
5
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
6
+ *.ftz filter=lfs diff=lfs merge=lfs -text
7
+ *.gz filter=lfs diff=lfs merge=lfs -text
8
+ *.h5 filter=lfs diff=lfs merge=lfs -text
9
+ *.joblib filter=lfs diff=lfs merge=lfs -text
10
+ *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
+ *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
+ *.model filter=lfs diff=lfs merge=lfs -text
13
+ *.msgpack filter=lfs diff=lfs merge=lfs -text
14
+ *.npy filter=lfs diff=lfs merge=lfs -text
15
+ *.npz filter=lfs diff=lfs merge=lfs -text
16
+ *.onnx filter=lfs diff=lfs merge=lfs -text
17
+ *.ot filter=lfs diff=lfs merge=lfs -text
18
+ *.parquet filter=lfs diff=lfs merge=lfs -text
19
+ *.pb filter=lfs diff=lfs merge=lfs -text
20
+ *.pickle filter=lfs diff=lfs merge=lfs -text
21
+ *.pkl filter=lfs diff=lfs merge=lfs -text
22
+ *.pt filter=lfs diff=lfs merge=lfs -text
23
+ *.pth filter=lfs diff=lfs merge=lfs -text
24
+ *.rar filter=lfs diff=lfs merge=lfs -text
25
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
26
+ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
+ *.tar.* filter=lfs diff=lfs merge=lfs -text
28
+ *.tflite filter=lfs diff=lfs merge=lfs -text
29
+ *.tgz filter=lfs diff=lfs merge=lfs -text
30
+ *.wasm filter=lfs diff=lfs merge=lfs -text
31
+ *.xz filter=lfs diff=lfs merge=lfs -text
32
+ *.zip filter=lfs diff=lfs merge=lfs -text
33
+ *.zst filter=lfs diff=lfs merge=lfs -text
34
+ *tfevents* filter=lfs diff=lfs merge=lfs -text
.github/README.md ADDED
@@ -0,0 +1 @@
 
 
1
+ ../README-main.md
.github/workflows/sync-to-hf.yaml ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: Sync to Hugging Face hub
2
+ on:
3
+ push:
4
+ branches: [main]
5
+
6
+ # to run this workflow manually from the Actions tab
7
+ workflow_dispatch:
8
+
9
+ jobs:
10
+ sync-to-hub:
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ - uses: actions/checkout@v3
14
+ with:
15
+ fetch-depth: 0
16
+ lfs: true
17
+ - name: Push to hub
18
+ env:
19
+ HF_TOKEN: ${{ secrets.HF_TOKEN }}
20
+ run: git push https://omkarenator:$HF_TOKEN@huggingface.co/spaces/AutoLLM/AutoAgents main
.gitignore ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+ .DS_Store
LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MIT License
2
+
3
+ Copyright (c) 2023 AutoLLM
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
README-main.md ADDED
@@ -0,0 +1,103 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # AutoAgents
2
+
3
+ <p align="center"><img src="https://raw.githubusercontent.com/AutoLLM/AutoAgents/assets/images/logo.png?raw=true" width=400/></p>
4
+
5
+ Unlock complex question answering in LLMs with enhanced chain-of-thought reasoning and information-seeking capabilities.
6
+
7
+ ## 👉 Overview
8
+
9
+ The purpose of this project is to extend LLMs ability to answer more complex questions through chain-of-thought reasoning and information-seeking actions.
10
+
11
+ We are excited to release the initial version of AutoAgents, a proof-of-concept on what can be achieved with only well-written prompts. This is the initial step towards our first big milestone, releasing and open-sourcing the AutoAgents 7B model!
12
+
13
+ Come try out our [Huggingface Space](https://huggingface.co/spaces/AutoLLM/AutoAgents)!
14
+
15
+
16
+
17
+ ## 🤖 The AutoAgents Project
18
+
19
+ This project demonstrates LLMs capability to execute a complex user goal: understand a user's goal, generate a plan, use proper tools, and deliver a final result.
20
+
21
+ For simplicity, our first attempt starts with a Web Search Agent.
22
+
23
+
24
+
25
+ ## 💫 How it works:
26
+
27
+ <p align="left"><img src="https://raw.githubusercontent.com/AutoLLM/AutoAgents/assets/images/agent.png" width=830/></p>
28
+
29
+
30
+
31
+ ## 📔 Examples
32
+
33
+ Ask your AutoAgent to do what a real person would do using the internet:
34
+
35
+ For example:
36
+
37
+ *1. Recommend a kid friendly movie that is playing at a theater near Sunnyvale. Give me the showtimes and a link to purchase the tickets*
38
+
39
+ *2. What is the average age of the past three president when they took office*
40
+
41
+ *3. What is the mortgage rate right now and how does that compare to the past two years*
42
+
43
+
44
+
45
+ ## 💁 Roadmap
46
+
47
+ * ~~HuggingFace Space demo using OpenAI models~~ [LINK](https://huggingface.co/spaces/AutoLLM/AutoAgents)
48
+ * AutoAgents [7B] Model
49
+ * Initial Release:
50
+ * Finetune and release a 7B parameter fine-tuned search model
51
+ * AutoAgents Dataset
52
+ * A high-quality dataset for a diverse set of search scenarios (why quality and diversity?<sup>[1](https://arxiv.org/abs/2305.11206)</sup>)
53
+ * Reduce Model Inference Overhead
54
+ * Affordance Modeling <sup>[2](https://en.wikipedia.org/wiki/Affordance)</sup>
55
+ * Extend Support to Additional Tools
56
+ * Customizable Document Search set (e.g. personal documents)
57
+ * Support Multi-turn Dialogue
58
+ * Advanced Flow Control in Plan Execution
59
+
60
+ We are actively developing a few interesting things, check back here or follow us on [Twitter](https://twitter.com/AutoLLM) for any new development.
61
+
62
+ If you are interested in any other problems, feel free to shoot us an issue.
63
+
64
+
65
+
66
+ ## 🧭 How to use this repo?
67
+
68
+ This repo contains the entire code to run the search agent from your local browser. All you need is an OpenAI API key to begin.
69
+
70
+ To run the search agent locally:
71
+
72
+ 1. Clone the repo and change the directory
73
+
74
+ ```bash
75
+ git clone https://github.com/AutoLLM/AutoAgents.git
76
+ cd AutoAgents
77
+ ```
78
+
79
+ 2. Install the dependencies
80
+
81
+ ```bash
82
+ pip install -r requirements.txt
83
+ ```
84
+
85
+ 3. Install the `autoagents` package
86
+
87
+ ```bash
88
+ pip install -e .
89
+ ```
90
+
91
+ 4. Make sure you have your OpenAI API key set as an environment variable. Alternatively, you can also feed it through the input text-box on the sidebar.
92
+
93
+ ```bash
94
+ export OPENAI_API_KEY=sk-xxxxxx
95
+ ```
96
+
97
+ 5. Run the Streamlit app
98
+
99
+ ```bash
100
+ streamlit run autoagents/spaces/app.py
101
+ ```
102
+
103
+ This should open a browser window where you can type your search query.
README.md ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: AutoAgents
3
+ emoji: 🐢
4
+ colorFrom: green
5
+ colorTo: purple
6
+ sdk: streamlit
7
+ sdk_version: 1.21.0
8
+ python_version: 3.10.11
9
+ app_file: autoagents/spaces/app.py
10
+ pinned: true
11
+ ---
12
+
13
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
autoagents/__init__.py ADDED
File without changes
autoagents/agents/__init__.py ADDED
File without changes
autoagents/agents/search.py ADDED
@@ -0,0 +1,267 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import List, Union, Any, Optional, Dict
2
+ import uuid
3
+ import re
4
+ from datetime import date
5
+ import asyncio
6
+ from collections import defaultdict
7
+ import os
8
+
9
+ from langchain.agents import Tool, AgentExecutor, LLMSingleActionAgent, AgentOutputParser
10
+ from langchain.prompts import StringPromptTemplate
11
+ from langchain import LLMChain
12
+ from langchain.chat_models import ChatOpenAI
13
+ from langchain.schema import AgentAction, AgentFinish
14
+ from langchain.callbacks import get_openai_callback
15
+ from langchain.callbacks.base import AsyncCallbackHandler
16
+ from langchain.callbacks.manager import AsyncCallbackManager
17
+
18
+
19
+ from autoagents.tools.tools import search_tool, note_tool, rewrite_search_query
20
+ from autoagents.utils.logger import InteractionsLogger
21
+ from autoagents.utils.utils import OpenAICred
22
+
23
+
24
+ # Set up the base template
25
+ template = """
26
+ We are working together to satisfy the user's original goal step-by-step. Play to your strengths as an LLM.
27
+ Make sure the plan is achievable using the
28
+ available tools. You SHOULD directly produce a `Final Answer:` when you
29
+ think you have good-enough information to achieve the Goal. The final answer should be descriptive should be descriptive, encompassing all relevant details..
30
+ Today is {today}.
31
+
32
+ ## Goal:
33
+ {input}
34
+
35
+ If you require assistance or additional information, you should use *only* one of the following tools:
36
+ {tools}.
37
+
38
+ ## Output format
39
+ You MUST produce Output in the following format:
40
+
41
+ Thought: you should always think about what to do when you think you have not achieved the Goal.
42
+ Reasoning: reasoning
43
+ Plan:
44
+ - short bulleted
45
+ - list that conveys
46
+ - next-step plan
47
+ Action: the action to take, should be ONE OF {tool_names}
48
+ Action Input: the input to the Action
49
+ Observation: the result of the Action
50
+ ... (this Thought/Reasoning/Plan/Action/Action Input/Observation can repeat N
51
+ times until there is a Final Answer)
52
+ Final Answer: the final answer to achieve the original Goal which can be the
53
+ only output or when you have no Action to do next.
54
+
55
+ ## History
56
+ {agent_scratchpad}
57
+
58
+ Do not repeat any past actions in History, because you will not get additional information.
59
+ If the last action is search, then you should use notepad to keep critical information.
60
+ If you have gathered all information in your plannings to satisfy the user's original goal, then respond immediately as the Final Answer.
61
+ """
62
+
63
+
64
+ # Set up a prompt template
65
+ class CustomPromptTemplate(StringPromptTemplate):
66
+ # The template to use
67
+ template: str
68
+ # The list of tools available
69
+ tools: List[Tool]
70
+ ialogger: InteractionsLogger
71
+
72
+ def format(self, **kwargs) -> str:
73
+ # Get the intermediate steps (AgentAction, Observation tuples)
74
+ # Format them in a particular way
75
+ intermediate_steps = kwargs.pop("intermediate_steps")
76
+ outputs = ""
77
+ # Set the agent_scratchpad variable to that value
78
+ for action, observation in intermediate_steps[:-1]:
79
+ outputs += f"{action.log}\n"
80
+ if len(intermediate_steps) > 0:
81
+ action, observation = intermediate_steps[-1]
82
+ # self.ialogger.add_system({"action": action, "observation": observation})
83
+ if action.tool not in ("Search", "Notepad"):
84
+ raise Exception("Invalid tool requested by the model.")
85
+ if action.tool == "Notepad":
86
+ outputs += f"{action.log}\n"
87
+ outputs += f"Observation: {observation}\n"
88
+ elif action.tool == "Search":
89
+ current = "".join([f"{d}" for d in observation])
90
+ outputs += f"{action.log}\n"
91
+ outputs += f"Observation: {current}\n"
92
+
93
+ # Parse the output ofr the last step for the reasoning and plan
94
+ regex = r"Thought\s*\d*\s*:(.*?)\n(.*)"
95
+ match = re.search(regex, action.log, re.DOTALL)
96
+ thoughts = match.group(1).strip() if match else ""
97
+
98
+ regex = r"Reasoning\s*\d*\s*:(.*?)\n(.*)"
99
+ match = re.search(regex, action.log, re.DOTALL)
100
+ reasoning = match.group(1).strip() if match else ""
101
+
102
+ regex = r"Plan\s*\d*\s*:(.*?)\nAction(.*)"
103
+ match = re.search(regex, action.log, re.DOTALL)
104
+ plans = match.group(1).strip() if match else ""
105
+ self.ialogger.add_structured_data({"output":{"thoughts": thoughts,
106
+ "reasoning": reasoning,
107
+ "plans": plans,
108
+ "action": action.tool,
109
+ "action_input": action.tool_input,
110
+ "raw_output":action.log},
111
+ "observation": observation})
112
+ kwargs["agent_scratchpad"] = outputs
113
+ # Create a tools variable from the list of tools provided
114
+ kwargs["tools"] = "\n".join([f"{tool.name}: {tool.description}" for tool in self.tools])
115
+ # Create a list of tool names for the tools provided
116
+ kwargs["tool_names"] = ", ".join([tool.name for tool in self.tools])
117
+ kwargs["today"] = date.today()
118
+ final_prompt = self.template.format(**kwargs)
119
+ self.ialogger.add_system({"value": final_prompt})
120
+ return final_prompt
121
+
122
+
123
+ class CustomOutputParser(AgentOutputParser):
124
+ class Config:
125
+ arbitrary_types_allowed = True
126
+ ialogger: InteractionsLogger
127
+ cred: OpenAICred
128
+ new_action_input: Optional[str]
129
+
130
+ action_history = defaultdict(set)
131
+
132
+ def parse(self, llm_output: str) -> Union[AgentAction, AgentFinish]:
133
+ self.ialogger.add_ai(llm_output)
134
+ # Check if agent should finish
135
+ if "Final Answer:" in llm_output:
136
+ final_answer = llm_output.split("Final Answer:")[-1].strip()
137
+ self.ialogger.add_structured_data({"output": {"action": "Final Answer",
138
+ "action_input": final_answer,
139
+ "raw_output": llm_output}})
140
+ return AgentFinish(
141
+ # Return values is generally always a dictionary with a single `output` key
142
+ # It is not recommended to try anything else at the moment :)
143
+ return_values={"output": final_answer},
144
+ log=llm_output,
145
+ )
146
+ # Parse out the action and action input
147
+ regex = r"Action\s*\d*\s*:(.*?)\nAction\s*\d*\s*Input\s*\d*\s*:[\s]*(.*)"
148
+ match = re.search(regex, llm_output, re.DOTALL)
149
+ if not match:
150
+ raise ValueError(f"Could not parse LLM output: `{llm_output}`")
151
+ action = match.group(1).strip()
152
+ action_input = match.group(2).strip().strip('"')
153
+
154
+ if action_input in self.action_history[action]:
155
+ new_action_input = rewrite_search_query(action_input,
156
+ self.action_history[action],
157
+ cred)
158
+ self.ialogger.add_message({"query_rewrite": True})
159
+ self.new_action_input = new_action_input
160
+ self.action_history[action].add(new_action_input)
161
+ return AgentAction(tool=action, tool_input=new_action_input, log=llm_output)
162
+ else:
163
+ # Return the action and action input
164
+ self.action_history[action].add(action_input)
165
+ return AgentAction(tool=action, tool_input=action_input, log=llm_output)
166
+
167
+
168
+ class ActionRunner:
169
+ def __init__(self,
170
+ outputq,
171
+ cred: OpenAICred,
172
+ model_name: str,
173
+ persist_logs: bool = False):
174
+ self.ialogger = InteractionsLogger(name=f"{uuid.uuid4().hex[:6]}", persist=persist_logs)
175
+ tools = [search_tool, note_tool]
176
+ prompt = CustomPromptTemplate(
177
+ template=template,
178
+ tools=tools,
179
+ input_variables=["input", "intermediate_steps"],
180
+ ialogger=self.ialogger)
181
+
182
+ output_parser = CustomOutputParser(ialogger=self.ialogger, cred=cred)
183
+
184
+ class MyCustomHandler(AsyncCallbackHandler):
185
+ def __init__(self):
186
+ pass
187
+
188
+ async def on_chain_end(self, outputs, **kwargs) -> None:
189
+ if "text" in outputs:
190
+ await outputq.put(outputs["text"])
191
+
192
+ async def on_agent_action(
193
+ self,
194
+ action: AgentAction,
195
+ *,
196
+ run_id: uuid.UUID,
197
+ parent_run_id: Optional[uuid.UUID] = None,
198
+ **kwargs: Any,
199
+ ) -> None:
200
+ if (new_action_input := output_parser.new_action_input):
201
+ # Notify users
202
+ await outputq.put(RuntimeWarning(f"Action Input Rewritten: {new_action_input}"))
203
+ output_parser.new_action_input = None
204
+
205
+ async def on_tool_start(
206
+ self,
207
+ serialized: Dict[str, Any],
208
+ input_str: str,
209
+ *,
210
+ run_id: uuid.UUID,
211
+ parent_run_id: Optional[uuid.UUID] = None,
212
+ **kwargs: Any,
213
+ ) -> None:
214
+ pass
215
+
216
+ async def on_tool_end(
217
+ self,
218
+ output: str,
219
+ *,
220
+ run_id: uuid.UUID,
221
+ parent_run_id: Optional[uuid.UUID] = None,
222
+ **kwargs: Any,
223
+ ) -> None:
224
+ await outputq.put(output)
225
+
226
+ handler = MyCustomHandler()
227
+
228
+ llm = ChatOpenAI(openai_api_key=cred.key,
229
+ openai_organization=cred.org,
230
+ temperature=0,
231
+ model_name=model_name)
232
+ llm_chain = LLMChain(llm=llm, prompt=prompt, callbacks=[handler])
233
+ tool_names = [tool.name for tool in tools]
234
+ for tool in tools:
235
+ tool.callbacks = [handler]
236
+
237
+ agent = LLMSingleActionAgent(
238
+ llm_chain=llm_chain,
239
+ output_parser=output_parser,
240
+ stop=["\nObservation:"],
241
+ allowed_tools=tool_names
242
+ )
243
+ callback_manager = AsyncCallbackManager([handler])
244
+
245
+ # Finally create the Executor
246
+ self.agent_executor = AgentExecutor.from_agent_and_tools(agent=agent,
247
+ tools=tools,
248
+ verbose=False,
249
+ callback_manager=callback_manager)
250
+
251
+ async def run(self, goal: str, outputq):
252
+ self.ialogger.set_goal(goal)
253
+ try:
254
+ with get_openai_callback() as cb:
255
+ output = await self.agent_executor.arun(goal)
256
+ self.ialogger.add_cost({"total_tokens": cb.total_tokens,
257
+ "prompt_tokens": cb.prompt_tokens,
258
+ "completion_tokens": cb.completion_tokens,
259
+ "total_cost": cb.total_cost,
260
+ "successful_requests": cb.successful_requests})
261
+ self.ialogger.save()
262
+ except Exception as e:
263
+ self.ialogger.add_message({"error": str(e)})
264
+ self.ialogger.save()
265
+ await outputq.put(e)
266
+ return
267
+ return output
autoagents/spaces/app.py ADDED
@@ -0,0 +1,145 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import asyncio
3
+ import random
4
+ from datetime import date, datetime, timezone, timedelta
5
+ from ast import literal_eval
6
+
7
+ import streamlit as st
8
+ import openai
9
+
10
+ from autoagents.utils.constants import MAIN_HEADER, MAIN_CAPTION, SAMPLE_QUESTIONS
11
+ from autoagents.agents.search import ActionRunner
12
+ from autoagents.utils.utils import OpenAICred
13
+
14
+ async def run():
15
+ output_acc = ""
16
+ st.session_state["random"] = random.randint(0, 99)
17
+ if "task" not in st.session_state:
18
+ st.session_state.task = None
19
+ if "model_name" not in st.session_state:
20
+ st.session_state.model_name = "gpt-3.5-turbo"
21
+
22
+ st.set_page_config(
23
+ page_title="Search Agent",
24
+ page_icon="🤖",
25
+ layout="wide",
26
+ initial_sidebar_state="expanded",
27
+ )
28
+
29
+ st.title(MAIN_HEADER)
30
+ st.caption(MAIN_CAPTION)
31
+
32
+ with st.form("my_form", clear_on_submit=False):
33
+ st.markdown("<style> .inter { white-space: pre-line; } </style>", unsafe_allow_html=True)
34
+ user_input = st.text_input(
35
+ "You: ",
36
+ key="input",
37
+ placeholder="Ask me anything ...",
38
+ label_visibility="hidden",
39
+ )
40
+
41
+ submitted = st.form_submit_button(
42
+ "Search", help="Hit to submit the search query."
43
+ )
44
+
45
+ # Ask the user to enter their OpenAI API key
46
+ if (api_key := st.sidebar.text_input("OpenAI api-key", type="password")):
47
+ cred = OpenAICred(api_key, None)
48
+ else:
49
+ cred = OpenAICred(os.getenv("OPENAI_API_KEY"),
50
+ os.getenv("OPENAI_API_ORG"))
51
+ with st.sidebar:
52
+ model_dict = {
53
+ "gpt-3.5-turbo": "GPT-3.5-turbo",
54
+ "gpt-4": "GPT-4 (Better but slower)",
55
+ }
56
+ st.radio(
57
+ "OpenAI model",
58
+ model_dict.keys(),
59
+ key="model_name",
60
+ format_func=lambda x: model_dict[x],
61
+ )
62
+
63
+ time_zone = str(datetime.now(timezone(timedelta(0))).astimezone().tzinfo)
64
+ st.markdown(f"**The system time zone is {time_zone} and the date is {date.today()}**")
65
+
66
+ st.markdown("**Example Queries:**")
67
+ for q in SAMPLE_QUESTIONS:
68
+ st.markdown(f"*{q}*")
69
+
70
+ if not cred.key:
71
+ st.warning(
72
+ "API key required to try this app. The API key is not stored in any form. [This](https://help.openai.com/en/articles/4936850-where-do-i-find-my-secret-api-key) might help."
73
+ )
74
+ else:
75
+ outputq = asyncio.Queue()
76
+ runner = ActionRunner(
77
+ outputq,
78
+ cred=cred,
79
+ model_name=st.session_state.model_name,
80
+ persist_logs=True,
81
+ ) # log to HF-dataset
82
+
83
+ async def cleanup(e):
84
+ st.error(e)
85
+ await st.session_state.task
86
+ st.session_state.task = None
87
+ st.stop()
88
+
89
+ placeholder = st.empty()
90
+
91
+ if user_input and submitted:
92
+ if st.session_state.task is not None:
93
+ with placeholder.container():
94
+ st.session_state.task.cancel()
95
+ st.warning("Previous search aborted", icon="⚠️")
96
+
97
+ st.session_state.task = asyncio.create_task(
98
+ runner.run(user_input, outputq)
99
+ )
100
+ iterations = 0
101
+ with st.expander("Search Results", expanded=True):
102
+ while True:
103
+ with st.spinner("Wait for it..."):
104
+ output = await outputq.get()
105
+ placeholder.empty()
106
+ if isinstance(output, Exception):
107
+ if isinstance(output, openai.error.AuthenticationError):
108
+ await cleanup(f"AuthenticationError: Invalid OpenAI API key.")
109
+ elif isinstance(output, openai.error.OpenAIError):
110
+ await cleanup(output)
111
+ elif isinstance(output, RuntimeWarning):
112
+ st.warning(output)
113
+ continue
114
+ else:
115
+ await cleanup("Something went wrong. Please try searching again.")
116
+ return
117
+ try:
118
+ output_fmt = literal_eval(output)
119
+ st.json(output_fmt, expanded=False)
120
+ st.write("---")
121
+ iterations += 1
122
+ except:
123
+ output_acc += "\n" + output
124
+ st.markdown(f"<div class=\"inter\"> {output} </div>",
125
+ unsafe_allow_html=True)
126
+ if iterations >= runner.agent_executor.max_iterations:
127
+ await cleanup(
128
+ f"Maximum iterations ({iterations}) exceeded. You can try running the search again or try a variation of the query."
129
+ )
130
+ return
131
+ if "Final Answer:" in output:
132
+ break
133
+ # Found the answer
134
+ final_answer = await st.session_state.task
135
+ final_answer = final_answer.replace("$", "\$")
136
+ # st.success accepts md
137
+ st.success(final_answer, icon="✅")
138
+ st.balloons()
139
+ st.session_state.task = None
140
+ st.stop()
141
+
142
+ if __name__ == "__main__":
143
+ loop = asyncio.new_event_loop()
144
+ loop.set_debug(enabled=False)
145
+ loop.run_until_complete(run())
autoagents/tools/__init__.py ADDED
File without changes
autoagents/tools/tools.py ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+
3
+ from duckpy import Client
4
+ from langchain import PromptTemplate, OpenAI, LLMChain
5
+ from langchain.agents import Tool
6
+ from langchain.chat_models import ChatOpenAI
7
+
8
+ from autoagents.utils.utils import OpenAICred
9
+
10
+
11
+ MAX_SEARCH_RESULTS = 20 # Number of search results to observe at a time
12
+
13
+ search_description = """ Useful for when you need to ask with search. Use direct language and be
14
+ EXPLICIT in what you want to search.
15
+
16
+ ## Examples of incorrect use
17
+ 1. Action: Search
18
+ Action Input: "[name of bagel shop] menu"
19
+
20
+ The Action Input cannot be None or empty.
21
+ """
22
+
23
+ notepad_description = """ Useful for when you need to note-down specific
24
+ information for later reference. Please provide full information you want to
25
+ note-down in the Action Input and all future prompts will remember it.
26
+ This is the mandatory tool after using the search tool.
27
+ Using Notepad does not always lead to a final answer.
28
+
29
+ ## Exampels of using notepad tool
30
+ Action: Notepad
31
+ Action Input: the information you want to note-down
32
+ """
33
+
34
+ async def ddg(query: str):
35
+ if query is None or query.lower().strip().strip('"') == "none" or query.lower().strip().strip('"') == "null":
36
+ x = "The action input field is empty. Please provide a search query."
37
+ return [x]
38
+ else:
39
+ client = Client()
40
+ return client.search(query)[:MAX_SEARCH_RESULTS]
41
+
42
+
43
+ async def notepad(x: str) -> str:
44
+ return f"{[x]}"
45
+
46
+
47
+ search_tool = Tool(name="Search",
48
+ func=lambda x: x,
49
+ coroutine=ddg,
50
+ description=search_description)
51
+
52
+ note_tool = Tool(name="Notepad",
53
+ func=lambda x: x,
54
+ coroutine=notepad,
55
+ description=notepad_description)
56
+
57
+
58
+ def rewrite_search_query(q: str, search_history, cred: OpenAICred) -> str:
59
+ history_string = '\n'.join(search_history)
60
+ template ="""We are using the Search tool.
61
+ # Previous queries:
62
+ {history_string}. \n\n Rewrite query {action_input} to be
63
+ different from the previous ones."""
64
+ llm = ChatOpenAI(temperature=0,
65
+ openai_api_key=cred.key,
66
+ openai_organization=cred.org)
67
+ prompt = PromptTemplate(template=template,
68
+ input_variables=["action_input", "history_string"])
69
+ llm_chain = LLMChain(prompt=prompt, llm=llm)
70
+ return llm_chain.predict(action_input=q, history_string=history_string)
autoagents/utils/__init__.py ADDED
File without changes
autoagents/utils/constants.py ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MAIN_HEADER = "Web Search Agent"
2
+
3
+ MAIN_CAPTION = """This is a proof-of-concept search agent that reasons, plans,
4
+ and executes web searches to collect information on your behalf. It aims to
5
+ resolve your question by breaking it down into step-by-step subtasks. All the
6
+ intermediate results will be presented.
7
+
8
+ *DISCLAIMER*: We are collecting search queries, so please refrain from
9
+ providing any personal information. If you wish to avoid this, you can run the
10
+ app locally by following the instructions on our
11
+ [Github](https://github.com/AutoLLM/AutoAgents)."""
12
+
13
+ SAMPLE_QUESTIONS = [
14
+ "Recommend me a movie in theater now to watch with kids.",
15
+ "Who is the most recent NBA MVP? Which team does he play for? What are his career stats?",
16
+ "Who is the head coach of AC Milan now? How long has he been coaching the team?",
17
+ "What is the mortgage rate right now and how does that compare to the past two years?",
18
+ "What is the weather like in San Francisco today? What about tomorrow?",
19
+ "When and where is the upcoming concert for Taylor Swift? Share a link to purchase tickets.",
20
+ "Find me recent studies focusing on hallucination in large language models. Provide the link to each study found.",
21
+ ]
autoagents/utils/logger.py ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import json
3
+ from typing import Dict, Any
4
+ import uuid
5
+ from datetime import datetime
6
+ import pytz
7
+
8
+ import huggingface_hub
9
+ from huggingface_hub import Repository
10
+
11
+
12
+ class InteractionsLogger:
13
+ def __init__(self, name: str, persist=False):
14
+ self.persist = persist
15
+ self.counter = 0
16
+ self.name = name # unique id
17
+ HF_TOKEN = os.environ.get("HF_TOKEN")
18
+ HF_DATASET_REPO_URL = os.environ.get("HF_DATASET_REPO_URL")
19
+ if (HF_TOKEN is not None) and (HF_DATASET_REPO_URL is not None):
20
+ self.repo = Repository(
21
+ local_dir="data", clone_from=HF_DATASET_REPO_URL, use_auth_token=HF_TOKEN
22
+ )
23
+ else:
24
+ self.persist = False
25
+
26
+ def set_goal(self, goal: str):
27
+ # Initialize two variables for saving two files (self.messages for
28
+ # training and self.structure_data for later use)
29
+ self.messages = [{"goal": goal}]
30
+ self.structured_data = {"goal": goal}
31
+
32
+ def add_system(self, more: Dict):
33
+ self.convos = [{"from": "system"} | more]
34
+
35
+ def add_ai(self, msg: str):
36
+ self.convos.append({"from": "ai", "value": msg})
37
+ self.messages.append({"id": f"{self.name}_{self.counter}", "conversations": self.convos})
38
+ self.counter += 1
39
+
40
+ def add_structured_data(self, data: Dict[str, Any]):
41
+ self.structured_data.update({f"turn_{self.counter}": data})
42
+
43
+ def add_message(self, data: Dict[str, Any]):
44
+ self.structured_data.update(data)
45
+
46
+ def save(self):
47
+ # add current datetime
48
+ self.add_message({"datetime": datetime.now(pytz.utc).strftime("%m/%d/%Y %H:%M:%S %Z%z")})
49
+ if self.persist:
50
+ # TODO: want to add retry in a loop?
51
+ self.repo.git_pull()
52
+ fname = uuid.uuid4().hex[:16]
53
+ with open(f"./data/{fname}.json", "w") as f:
54
+ json.dump(self.messages, f, indent=2)
55
+ with open(f"./data/{fname}.clean.json", "w") as f:
56
+ json.dump(self.structured_data, f, indent=2)
57
+ commit_url = self.repo.push_to_hub()
58
+
59
+ def add_cost(self, cost):
60
+ self.messages.append({"metrics": cost})
autoagents/utils/utils.py ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ from dataclasses import dataclass
2
+ from typing import Optional
3
+
4
+
5
+ @dataclass
6
+ class OpenAICred:
7
+ key: str
8
+ org: Optional[str]
requirements.txt ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ openai>=0.27.7
2
+ langchain>=0.0.193
3
+ duckpy
4
+ huggingface_hub
5
+ pytz
setup.py ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ from setuptools import setup, find_packages
2
+
3
+ setup(
4
+ name='autoagents',
5
+ version='0.1.0',
6
+ packages=find_packages(include=['autoagents', 'autoagents.*'])
7
+ )
test.py ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import asyncio
3
+ from autoagents.agents.search import ActionRunner
4
+ from langchain.callbacks import get_openai_callback
5
+ from pprint import pprint
6
+ import pdb
7
+ from ast import literal_eval
8
+ from multiprocessing import Pool, TimeoutError
9
+
10
+ async def work(user_input):
11
+ outputq = asyncio.Queue()
12
+
13
+ API_O = os.getenv("OPENAI_API_KEY")
14
+ runner = ActionRunner(outputq, api_key=API_O, model_name="gpt-3.5-turbo")
15
+ task = asyncio.create_task(runner.run(user_input, outputq))
16
+
17
+ while True:
18
+ output = await outputq.get()
19
+ if isinstance(output, Exception):
20
+ print(output)
21
+ return
22
+ try:
23
+ pprint(literal_eval(output))
24
+ except:
25
+ print(output)
26
+ print("-----------------------------------------------------------")
27
+ if "Final Answer:" in output:
28
+ break
29
+ await task
30
+
31
+ Q = [
32
+ "list 5 cities and their current populations where Paramore is playing this year.",
33
+ "Who is Leo DiCaprio's girlfriend? What is her current age raised to the 0.43 power?",
34
+ "How many watermelons can fit in a Tesla Model S?",
35
+ "Recommend me some laptops suitable for UI designers under $2000. Please include brand and price."
36
+ "Build me a vacation plan for Rome and Milan this summer for seven days. Include place to visit and hotels to stay. ",
37
+ "What is the sum of ages of the wives of Barack Obama and Donald Trump?",
38
+ "Who is the most recent NBA MVP? Which team does he play for? What is his season stats?",
39
+ "What were the scores for the last three games for the Los Angeles Lakers? Provide the dates and opposing teams.",
40
+ "Which team won in women's volleyball in the Summer Olympics that was held in London?",
41
+ "Provide a summary of the latest COVID-19 research paper published. Include the title, authors and abstract.",
42
+ "What is the top grossing movie in theatres this week? Provide the movie title, director, and a brief synopsis of the movie's plot. Attach a review for this movie.",
43
+ "Recommend a bagel shop near the Strip district in Pittsburgh that offer vegan food",
44
+ "Who are some top researchers in the field of machine learning systems nowadays?"
45
+ ]
46
+
47
+ def main(q):
48
+ asyncio.run(work(q))
49
+
50
+ if __name__ == "__main__":
51
+ with Pool(processes=10) as pool:
52
+ print(pool.map(main, Q))