Skip to content

Commit 2ac07f4

Browse files
authored
Merge branch 'OpenInterpreter:main' into main
2 parents 217b1eb + c81d910 commit 2ac07f4

File tree

7 files changed

+1249
-1347
lines changed

7 files changed

+1249
-1347
lines changed

interpreter/core/async_core.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ def __init__(self, *args, **kwargs):
6060
self.server = Server(self)
6161

6262
# For the 01. This lets the OAI compatible server accumulate context before responding.
63-
self.context_mode = False
63+
self.context_mode = True
6464

6565
async def input(self, chunk):
6666
"""
@@ -737,6 +737,7 @@ async def openai_compatible_generator():
737737
for i, chunk in enumerate(
738738
async_interpreter.chat(message=message, stream=True, display=True)
739739
):
740+
await asyncio.sleep(0) # Yield control to the event loop
740741
made_chunk = True
741742

742743
if async_interpreter.stop_event.is_set():
@@ -832,6 +833,11 @@ async def chat_completion(request: ChatCompletionRequest):
832833
# Remove that {START} message that would have just been added
833834
async_interpreter.messages = async_interpreter.messages[:-1]
834835
last_start_time = time.time()
836+
if (
837+
async_interpreter.messages
838+
and async_interpreter.messages[-1].get("role") != "user"
839+
):
840+
return
835841
else:
836842
# Check if we're within 6 seconds of last_start_time
837843
current_time = time.time()

interpreter/core/computer/browser/browser.py

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import threading
12
import time
23

34
import html2text
@@ -34,6 +35,33 @@ def search(self, query):
3435
)
3536
return response.json()["result"]
3637

38+
def fast_search(self, query):
39+
"""
40+
Searches the web for the specified query and returns the results.
41+
"""
42+
43+
# Start the request in a separate thread
44+
response_thread = threading.Thread(
45+
target=lambda: setattr(
46+
threading.current_thread(),
47+
"response",
48+
requests.get(
49+
f'{self.computer.api_base.strip("/")}/browser/search',
50+
params={"query": query},
51+
),
52+
)
53+
)
54+
response_thread.start()
55+
56+
# Perform the Google search
57+
self.search_google(query, delays=False)
58+
59+
# Wait for the request to complete and get the result
60+
response_thread.join()
61+
response = response_thread.response
62+
63+
return response.json()["result"]
64+
3765
def setup(self):
3866
self.service = Service(ChromeDriverManager().install())
3967
self.options = webdriver.ChromeOptions()
@@ -42,9 +70,9 @@ def setup(self):
4270
def go_to_url(self, url):
4371
"""Navigate to a URL"""
4472
self.driver.get(url)
45-
time.sleep(3)
73+
time.sleep(1)
4674

47-
def search_google(self, query):
75+
def search_google(self, query, delays=True):
4876
"""Perform a Google search"""
4977
self.driver.get("https://www.perplexity.ai")
5078
# search_box = self.driver.find_element(By.NAME, 'q')
@@ -56,13 +84,16 @@ def search_google(self, query):
5684
active_element = self.driver.switch_to.active_element
5785
active_element.send_keys(query)
5886
active_element.send_keys(Keys.RETURN)
59-
time.sleep(5)
87+
if delays:
88+
time.sleep(3)
6089

6190
def analyze_page(self, intent):
6291
"""Extract HTML, list interactive elements, and analyze with AI"""
6392
html_content = self.driver.page_source
6493
text_content = html2text.html2text(html_content)
6594

95+
# text_content = text_content[:len(text_content)//2]
96+
6697
elements = (
6798
self.driver.find_elements(By.TAG_NAME, "a")
6899
+ self.driver.find_elements(By.TAG_NAME, "button")

interpreter/core/computer/skills/skills.py

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,7 @@ class Skills:
2424
def __init__(self, computer):
2525
self.computer = computer
2626
self.path = str(Path(oi_dir) / "skills")
27-
self.new_skill = NewSkill()
28-
self.new_skill.path = self.path
27+
self.new_skill = NewSkill(self)
2928

3029
def list(self):
3130
return [
@@ -97,8 +96,9 @@ def import_skills(self):
9796

9897

9998
class NewSkill:
100-
def __init__(self):
99+
def __init__(self, skills):
101100
self.path = ""
101+
self.skills = skills
102102

103103
def create(self):
104104
self.steps = []
@@ -180,18 +180,27 @@ def {normalized_name}(step=0):
180180
if step + 1 < len(steps):
181181
print("After completing the above, I need you to run {normalized_name}(step=" + str(step + 1) + ") immediatly.")
182182
else:
183-
print("You have completed all the steps, the task/skill has been run!")
183+
print("After executing the code, you have completed all the steps, the task/skill has been run!")
184184
else:
185185
print("The specified step number exceeds the available steps. Please run with a valid step number.")
186186
'''.strip()
187187

188-
if not os.path.exists(self.path):
189-
os.makedirs(self.path)
190-
with open(self.path + "/" + normalized_name + ".py", "w") as file:
188+
skill_file_path = os.path.join(self.skills.path, f"{normalized_name}.py")
189+
190+
if not os.path.exists(self.skills.path):
191+
os.makedirs(self.skills.path)
192+
193+
with open(skill_file_path, "w") as file:
191194
file.write(skill_string)
192195

193-
print("SKILL SAVED:", self.name.upper())
196+
# Execute the code in skill_string to define the function
197+
exec(skill_string)
194198

195-
print(
196-
"Teaching session finished. Tell the user that the skill above has been saved. Great work!"
197-
)
199+
# Verify that the file was written
200+
if os.path.exists(skill_file_path):
201+
print("SKILL SAVED:", self.name.upper())
202+
print(
203+
"Teaching session finished. Tell the user that the skill above has been saved. Great work!"
204+
)
205+
else:
206+
print(f"Error: Failed to write skill file to {skill_file_path}")

interpreter/core/computer/terminal/languages/jupyter_language.py

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
import time
1414
import traceback
1515

16+
os.environ["LITELLM_LOCAL_MODEL_COST_MAP"] = "True"
17+
import litellm
1618
from jupyter_client import KernelManager
1719

1820
from ..base_language import BaseLanguage
@@ -88,6 +90,9 @@ def run(self, code):
8890
while not self.kc.is_alive():
8991
time.sleep(0.1)
9092

93+
self.last_output_time = time.time()
94+
self.last_output_message_time = time.time()
95+
9196
################################################################
9297
### OFFICIAL OPEN INTERPRETER GOVERNMENT ISSUE SKILL LIBRARY ###
9398
################################################################
@@ -144,7 +149,52 @@ def iopub_message_listener():
144149
self.finish_flag = True
145150
return
146151
try:
152+
if (
153+
time.time() - self.last_output_time > 15
154+
and time.time() - self.last_output_message_time > 15
155+
):
156+
self.last_output_message_time = time.time()
157+
158+
text = f"{self.computer.interpreter.messages}\n\nThe program above has been running for over 15 seconds. It might require user input. Are there keystrokes that the user should type in, to proceed after the last command?"
159+
if time.time() - self.last_output_time > 500:
160+
text += f" If you think the process is frozen, or that the user wasn't expect it to run for this long (it has been {time.time() - self.last_output_time} seconds since last output) then say <input>CTRL-C</input>."
161+
162+
messages = [
163+
{
164+
"role": "system",
165+
"type": "message",
166+
"content": "You are an expert programming assistant. You will help the user determine if they should enter input into the terminal, per the user's requests. If you think the user would want you to type something into stdin, enclose it in <input></input> XML tags, like <input>y</input> to type 'y'.",
167+
},
168+
{"role": "user", "type": "message", "content": text},
169+
]
170+
params = {
171+
"messages": messages,
172+
"model": self.computer.interpreter.llm.model,
173+
"stream": True,
174+
"temperature": 0,
175+
}
176+
if self.computer.interpreter.llm.api_key:
177+
params["api_key"] = self.computer.interpreter.llm.api_key
178+
179+
response = ""
180+
for chunk in litellm.completion(**params):
181+
content = chunk.choices[0].delta.content
182+
if type(content) == str:
183+
response += content
184+
185+
# Parse the response for input tags
186+
input_match = re.search(r"<input>(.*?)</input>", response)
187+
if input_match:
188+
user_input = input_match.group(1)
189+
# Check if the user input is CTRL-C
190+
self.finish_flag = True
191+
if user_input.upper() == "CTRL-C":
192+
self.finish_flag = True
193+
else:
194+
self.kc.input(user_input)
195+
147196
msg = self.kc.iopub_channel.get_msg(timeout=0.05)
197+
self.last_output_time = time.time()
148198
except queue.Empty:
149199
continue
150200
except Exception as e:
@@ -255,7 +305,10 @@ def detect_active_line(self, line):
255305
# Split the line by "##active_line" and grab the last element
256306
last_active_line = line.split("##active_line")[-1]
257307
# Split the last active line by "##" and grab the first element
258-
active_line = int(last_active_line.split("##")[0])
308+
try:
309+
active_line = int(last_active_line.split("##")[0])
310+
except:
311+
active_line = 0
259312
# Remove all ##active_line{number}##\n
260313
line = re.sub(r"##active_line\d+##\n", "", line)
261314
return line, active_line
@@ -279,6 +332,7 @@ def _capture_output(self, message_queue):
279332
if DEBUG_MODE:
280333
print(output)
281334
yield output
335+
282336
except queue.Empty:
283337
if self.finish_flag:
284338
time.sleep(0.1)

0 commit comments

Comments
 (0)