johann22 commited on
Commit
1128fce
1 Parent(s): 84df34e

Create agent.py

Browse files
Files changed (1) hide show
  1. agent.py +131 -284
agent.py CHANGED
@@ -1,284 +1,131 @@
1
- import os
2
- import subprocess
3
-
4
- import openai
5
-
6
- from agent.prompts import (
7
- ACTION_PROMPT,
8
- ADD_PROMPT,
9
- COMPRESS_HISTORY_PROMPT,
10
- LOG_PROMPT,
11
- LOG_RESPONSE,
12
- MODIFY_PROMPT,
13
- PREFIX,
14
- READ_PROMPT,
15
- TASK_PROMPT,
16
- UNDERSTAND_TEST_RESULTS_PROMPT,
17
- )
18
- from agent.utils import parse_action, parse_file_content, read_python_module_structure
19
-
20
- VERBOSE = False
21
- MAX_HISTORY = 100
22
- MODEL = "gpt-3.5-turbo" # "gpt-4"
23
-
24
-
25
- def run_gpt(
26
- prompt_template,
27
- stop_tokens,
28
- max_tokens,
29
- module_summary,
30
- purpose,
31
- **prompt_kwargs,
32
- ):
33
- content = PREFIX.format(
34
- module_summary=module_summary,
35
- purpose=purpose,
36
- ) + prompt_template.format(**prompt_kwargs)
37
- if VERBOSE:
38
- print(LOG_PROMPT.format(content))
39
- resp = openai.ChatCompletion.create(
40
- model=MODEL,
41
- messages=[
42
- {"role": "system", "content": content},
43
- ],
44
- temperature=0.0,
45
- max_tokens=max_tokens,
46
- stop=stop_tokens if stop_tokens else None,
47
- )["choices"][0]["message"]["content"]
48
- if VERBOSE:
49
- print(LOG_RESPONSE.format(resp))
50
- return resp
51
-
52
-
53
- def compress_history(purpose, task, history, directory):
54
- module_summary, _, _ = read_python_module_structure(directory)
55
- resp = run_gpt(
56
- COMPRESS_HISTORY_PROMPT,
57
- stop_tokens=["observation:", "task:", "action:", "thought:"],
58
- max_tokens=512,
59
- module_summary=module_summary,
60
- purpose=purpose,
61
- task=task,
62
- history=history,
63
- )
64
- history = "observation: {}\n".format(resp)
65
- return history
66
-
67
-
68
- def call_main(purpose, task, history, directory, action_input):
69
- module_summary, _, _ = read_python_module_structure(directory)
70
- resp = run_gpt(
71
- ACTION_PROMPT,
72
- stop_tokens=["observation:", "task:"],
73
- max_tokens=256,
74
- module_summary=module_summary,
75
- purpose=purpose,
76
- task=task,
77
- history=history,
78
- )
79
- lines = resp.strip().strip("\n").split("\n")
80
- for line in lines:
81
- if line == "":
82
- continue
83
- if line.startswith("thought: "):
84
- history += "{}\n".format(line)
85
- elif line.startswith("action: "):
86
- action_name, action_input = parse_action(line)
87
- history += "{}\n".format(line)
88
- return action_name, action_input, history, task
89
- else:
90
- assert False, "unknown action: {}".format(line)
91
- return "MAIN", None, history, task
92
-
93
-
94
- def call_test(purpose, task, history, directory, action_input):
95
- result = subprocess.run(
96
- ["python", "-m", "pytest", "--collect-only", directory],
97
- capture_output=True,
98
- text=True,
99
- )
100
- if result.returncode != 0:
101
- history += "observation: there are no tests! Test should be written in a test folder under {}\n".format(
102
- directory
103
- )
104
- return "MAIN", None, history, task
105
- result = subprocess.run(
106
- ["python", "-m", "pytest", directory], capture_output=True, text=True
107
- )
108
- if result.returncode == 0:
109
- history += "observation: tests pass\n"
110
- return "MAIN", None, history, task
111
- module_summary, content, _ = read_python_module_structure(directory)
112
- resp = run_gpt(
113
- UNDERSTAND_TEST_RESULTS_PROMPT,
114
- stop_tokens=[],
115
- max_tokens=256,
116
- module_summary=module_summary,
117
- purpose=purpose,
118
- task=task,
119
- history=history,
120
- stdout=result.stdout[:5000], # limit amount of text
121
- stderr=result.stderr[:5000], # limit amount of text
122
- )
123
- history += "observation: tests failed: {}\n".format(resp)
124
- return "MAIN", None, history, task
125
-
126
-
127
- def call_set_task(purpose, task, history, directory, action_input):
128
- module_summary, content, _ = read_python_module_structure(directory)
129
- task = run_gpt(
130
- TASK_PROMPT,
131
- stop_tokens=[],
132
- max_tokens=64,
133
- module_summary=module_summary,
134
- purpose=purpose,
135
- task=task,
136
- history=history,
137
- ).strip("\n")
138
- history += "observation: task has been updated to: {}\n".format(task)
139
- return "MAIN", None, history, task
140
-
141
-
142
- def call_read(purpose, task, history, directory, action_input):
143
- if not os.path.exists(action_input):
144
- history += "observation: file does not exist\n"
145
- return "MAIN", None, history, task
146
- module_summary, content, _ = read_python_module_structure(directory)
147
- f_content = (
148
- content[action_input] if content[action_input] else "< document is empty >"
149
- )
150
- resp = run_gpt(
151
- READ_PROMPT,
152
- stop_tokens=[],
153
- max_tokens=256,
154
- module_summary=module_summary,
155
- purpose=purpose,
156
- task=task,
157
- history=history,
158
- file_path=action_input,
159
- file_contents=f_content,
160
- ).strip("\n")
161
- history += "observation: {}\n".format(resp)
162
- return "MAIN", None, history, task
163
-
164
-
165
- def call_modify(purpose, task, history, directory, action_input):
166
- if not os.path.exists(action_input):
167
- history += "observation: file does not exist\n"
168
- return "MAIN", None, history, task
169
- (
170
- module_summary,
171
- content,
172
- _,
173
- ) = read_python_module_structure(directory)
174
- f_content = (
175
- content[action_input] if content[action_input] else "< document is empty >"
176
- )
177
- resp = run_gpt(
178
- MODIFY_PROMPT,
179
- stop_tokens=["action:", "thought:", "observation:"],
180
- max_tokens=2048,
181
- module_summary=module_summary,
182
- purpose=purpose,
183
- task=task,
184
- history=history,
185
- file_path=action_input,
186
- file_contents=f_content,
187
- )
188
- new_contents, description = parse_file_content(resp)
189
- if new_contents is None:
190
- history += "observation: failed to modify file\n"
191
- return "MAIN", None, history, task
192
-
193
- with open(action_input, "w") as f:
194
- f.write(new_contents)
195
-
196
- history += "observation: file successfully modified\n"
197
- history += "observation: {}\n".format(description)
198
- return "MAIN", None, history, task
199
-
200
-
201
- def call_add(purpose, task, history, directory, action_input):
202
- d = os.path.dirname(action_input)
203
- if not d.startswith(directory):
204
- history += "observation: files must be under directory {}\n".format(directory)
205
- elif not action_input.endswith(".py"):
206
- history += "observation: can only write .py files\n"
207
- else:
208
- if d and not os.path.exists(d):
209
- os.makedirs(d)
210
- if not os.path.exists(action_input):
211
- module_summary, _, _ = read_python_module_structure(directory)
212
- resp = run_gpt(
213
- ADD_PROMPT,
214
- stop_tokens=["action:", "thought:", "observation:"],
215
- max_tokens=2048,
216
- module_summary=module_summary,
217
- purpose=purpose,
218
- task=task,
219
- history=history,
220
- file_path=action_input,
221
- )
222
- new_contents, description = parse_file_content(resp)
223
- if new_contents is None:
224
- history += "observation: failed to write file\n"
225
- return "MAIN", None, history, task
226
-
227
- with open(action_input, "w") as f:
228
- f.write(new_contents)
229
-
230
- history += "observation: file successfully written\n"
231
- history += "obsertation: {}\n".format(description)
232
- else:
233
- history += "observation: file already exists\n"
234
- return "MAIN", None, history, task
235
-
236
-
237
- NAME_TO_FUNC = {
238
- "MAIN": call_main,
239
- "UPDATE-TASK": call_set_task,
240
- "MODIFY-FILE": call_modify,
241
- "READ-FILE": call_read,
242
- "ADD-FILE": call_add,
243
- "TEST": call_test,
244
- }
245
-
246
-
247
- def run_action(purpose, task, history, directory, action_name, action_input):
248
- if action_name == "COMPLETE":
249
- exit(0)
250
-
251
- # compress the history when it is long
252
- if len(history.split("\n")) > MAX_HISTORY:
253
- if VERBOSE:
254
- print("COMPRESSING HISTORY")
255
- history = compress_history(purpose, task, history, directory)
256
-
257
- assert action_name in NAME_TO_FUNC
258
-
259
- print("RUN: ", action_name, action_input)
260
- return NAME_TO_FUNC[action_name](purpose, task, history, directory, action_input)
261
-
262
-
263
- def run(purpose, directory, task=None):
264
- history = ""
265
- action_name = "UPDATE-TASK" if task is None else "MAIN"
266
- action_input = None
267
- while True:
268
- print("")
269
- print("")
270
- print("---")
271
- print("purpose:", purpose)
272
- print("task:", task)
273
- print("---")
274
- print(history)
275
- print("---")
276
-
277
- action_name, action_input, history, task = run_action(
278
- purpose,
279
- task,
280
- history,
281
- directory,
282
- action_name,
283
- action_input,
284
- )
 
1
+ PREFIX = """You are an expert online researcher
2
+ You are working on the task outlined here
3
+ Purpose:
4
+ {purpose}
5
+ """
6
+
7
+ ACTION_PROMPT = """
8
+ You have access to the following tools:
9
+ - action: UPDATE-TASK action_input=NEW_TASK
10
+ - action: SEARCH action_input=PAGE_URL
11
+ - action: COMPLETE
12
+ Instructions
13
+ - Write a response satisfying the request
14
+ - Set action: SEARCH action_input=URL of the page you need to search
15
+ - Complete the current task as best you can
16
+ - When the task is complete, update the task
17
+ - SEARCH to verify that information you are providing
18
+ Use the following format:
19
+ task: the input task you must complete
20
+ thought: you should always think about what to do
21
+ action: the action to take (should be one of [UPDATE-TASK, SEARCH, COMPLETE]) action_input=XXX
22
+ observation: the result of the action
23
+ thought: you should always think after an observation
24
+ action: always perform a SEARCH to verify your observation
25
+ ... (thought/action/observation/thought can repeat N times)
26
+ You are attempting to complete the task
27
+ task: {task}
28
+ {history}"""
29
+
30
+ SEARCH_QUERY = """
31
+ You are attempting to complete the task
32
+ task: {task}
33
+ Progress:
34
+ {history}
35
+ What is the URL for the webpage that I need to search for information on?
36
+ URL:"""
37
+
38
+ GOOGLE_SEARCH_QUERY = """
39
+ You are attempting to complete the task
40
+ task: {task}
41
+ Progress:
42
+ {history}
43
+ What information needs to be searched for on Google to help complete the task?
44
+ Query:"""
45
+
46
+
47
+ TASK_PROMPT = """
48
+ You are attempting to complete the task
49
+ task: {task}
50
+ Progress:
51
+ {history}
52
+ Tasks should be small, isolated, and independent
53
+ What should the task be for us to achieve the purpose?
54
+ task: """
55
+
56
+ READ_PROMPT = """
57
+ You are attempting to complete the task
58
+ task: {task}
59
+ Progress:
60
+ {history}
61
+ {file_path}
62
+ ---
63
+ {file_contents}
64
+ ---
65
+ Return your thoughts about the file relevant to completing the task (in a paragraph)
66
+ Mention any specific functions, arguments, or details needed
67
+ """
68
+
69
+ ADD_PROMPT = """
70
+ You are attempting to complete the task
71
+ task: {task}
72
+ Progress:
73
+ {history}
74
+ Write a new file called {file_path} with contents between ---
75
+ After the contents write a paragraph on what was inserted with details
76
+ """
77
+
78
+ MODIFY_PROMPT = """
79
+ You are attempting to complete the task
80
+ task: {task}
81
+ Progress:
82
+ {history}
83
+ {file_path}
84
+ ---
85
+ {file_contents}
86
+ ---
87
+ Return the complete modified {file_path} contents between ---
88
+ After the contents write a paragraph on what was changed with details
89
+ """
90
+
91
+
92
+ UNDERSTAND_TEST_RESULTS_PROMPT = """
93
+ You are attempting to complete the task
94
+ task: {task}
95
+ Progress:
96
+ {history}
97
+ Test results:
98
+ STDOUT
99
+ ---
100
+ {stdout}
101
+ ---
102
+ STDERR
103
+ ---
104
+ {stderr}
105
+ ---
106
+ Describe why the tests failed and how to fix them (in a paragraph)
107
+ """
108
+
109
+
110
+ COMPRESS_HISTORY_PROMPT = """
111
+ You are attempting to complete the task
112
+ task: {task}
113
+ Progress:
114
+ {history}
115
+ Compress the timeline of progress above into a single summary (as a paragraph)
116
+ Include all important milestones, the current challenges, and implementation details necessary to proceed
117
+ """
118
+
119
+ LOG_PROMPT = """
120
+ PROMPT
121
+ **************************************
122
+ {}
123
+ **************************************
124
+ """
125
+
126
+ LOG_RESPONSE = """
127
+ RESPONSE
128
+ **************************************
129
+ {}
130
+ **************************************
131
+ """