mirror of
https://github.com/OS-Copilot/OS-Copilot.git
synced 2026-05-05 03:00:15 -04:00
Merge branch 'new_infra_zy' of https://github.com/LividWo/jarvis into new_infra_zy
pull new_infra_zy
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
from jarvis.agent.openai_agent import OpenAIAgent
|
||||
from jarvis.enviroment.base_env import BaseEnviroment
|
||||
from jarvis.enviroment.old_env import BaseEnviroment
|
||||
|
||||
'''
|
||||
A minimal example for base env and openai agent
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from jarvis.agent.openai_agent import OpenAIAgent
|
||||
from jarvis.enviroment.base_env import BaseEnviroment
|
||||
from jarvis.enviroment.old_env import BaseEnviroment
|
||||
|
||||
'''
|
||||
A minimal example for base env and openai agent
|
||||
@@ -23,8 +23,7 @@ for a in action:
|
||||
print(environment.step(command))
|
||||
# time.sleep(2)
|
||||
|
||||
from jarvis.action_lib.execute_sql import execute_sql
|
||||
from jarvis.action_lib.execute_sql import ExecuteSQL
|
||||
|
||||
action = execute_sql()
|
||||
action.run(db_path='../tasks/travel/database/travel.db',
|
||||
query='SELECT * FROM railway\nWHERE number="D1000";')
|
||||
action = ExecuteSQL()
|
||||
action(query='SELECT * FROM railway\nWHERE number="D1000";')
|
||||
|
||||
55
examples/3_py_interpreter.py
Normal file
55
examples/3_py_interpreter.py
Normal file
@@ -0,0 +1,55 @@
|
||||
from jarvis.action_lib.python_interpreter import PythonInterpreter, DEFAULT_DESCRIPTION
|
||||
|
||||
|
||||
# a = PythonInterpreter()
|
||||
# a(DEFAULT_DESCRIPTION)
|
||||
|
||||
import subprocess
|
||||
import os
|
||||
|
||||
# 执行 cd 命令
|
||||
current_dir = os.getcwd()
|
||||
print("当前工作目录:", current_dir)
|
||||
|
||||
command = 'gogogo && cd .. && pwd'
|
||||
result = subprocess.run(command, shell=True, capture_output=True, text=True)
|
||||
stout = result.stdout.strip().split('\n')
|
||||
out = "\n".join(stout[:-1])
|
||||
pwd = stout[-1]
|
||||
|
||||
print("out", out)
|
||||
print("pwd", pwd)
|
||||
print(result.stderr)
|
||||
|
||||
# 打印当前目录
|
||||
print("当前目录:", current_dir)
|
||||
#
|
||||
# self.env_state = EnvState()
|
||||
# self.env_state.command.append(_command)
|
||||
# command = _command + self.log_execute
|
||||
# subprocess.run(["tmux", "send-keys", "-t", self.server_name, command, "Enter"])
|
||||
# time.sleep(self.timeout)
|
||||
# self.observe()
|
||||
# return self.env_state
|
||||
#
|
||||
#
|
||||
# command = "pwd" + self.log_state
|
||||
# subprocess.run(["tmux", "send-keys", "-t", self.server_name, command, "Enter"])
|
||||
# time.sleep(1)
|
||||
# self.env_state.pwd = self.read_log(self.state_log_path)
|
||||
# self.working_dir = self.env_state.pwd[0].strip()
|
||||
# # print("working dir:", self.working_dir)
|
||||
# result = subprocess.run(['ls'], cwd=self.working_dir, capture_output=True, text=True)
|
||||
# self.env_state.ls = [result.stdout]
|
||||
# # 输出执行结果
|
||||
# # print(result.stdout)
|
||||
# # for _command in ["pwd", "ls"]:
|
||||
# # command = _command + self.log_state
|
||||
# # subprocess.run(["tmux", "send-keys", "-t", self.server_name, command, "Enter"])
|
||||
# # # todo 处理异步的问题,可能提交过去还没执行完。
|
||||
# # time.sleep(self.timeout)
|
||||
# # if _command == "pwd":
|
||||
# # self.env_state.pwd = self.read_log(self.state_log_path)
|
||||
# # else:
|
||||
# # self.env_state.ls = self.read_log(self.state_log_path)
|
||||
# self.env_state.result = self.read_log(self.execute_log_path)
|
||||
2
index.py
2
index.py
@@ -1,5 +1,5 @@
|
||||
import time
|
||||
from jarvis.enviroment.base_env import BaseEnviroment
|
||||
from jarvis.enviroment.old_env import BaseEnviroment
|
||||
from jarvis.agent.openai_agent import OpenAIAgent
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import subprocess
|
||||
import time
|
||||
import os
|
||||
from typing import Optional
|
||||
from typing import Optional, Union
|
||||
import textwrap
|
||||
from jarvis.core.schema import ActionReturn, ActionStatusCode
|
||||
|
||||
@@ -19,19 +19,18 @@ class BaseAction:
|
||||
def __init__(self,
|
||||
description: Optional[str] = None,
|
||||
name: Optional[str] = None,
|
||||
timeout: Optional[int] = 2) -> None:
|
||||
timeout: int = 2,
|
||||
action_type: Optional[str] = 'BASH') -> None:
|
||||
if name is None:
|
||||
name = self.__class__.__name__
|
||||
self._name = name
|
||||
self._description = description
|
||||
self._timeout = timeout
|
||||
# self.execute_log_path = execute_log_path
|
||||
# self.state_log_path = state_log_path
|
||||
# self.log_execute = logging_command + self.execute_log_path
|
||||
# self.log_state = logging_command + self.state_log_path
|
||||
# self.working_dir = os.path.abspath(os.path.join(os.getcwd(), "..", "..", "working_dir"))
|
||||
# self.server_name = "test"
|
||||
# print(self.working_dir)
|
||||
assert action_type in ['BASH', 'CODE', 'TOOL']
|
||||
self.action_type = action_type
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
raise NotImplementedError
|
||||
|
||||
def _python(self, *lines):
|
||||
return f'python -Bc "{"; ".join(lines)}"'
|
||||
@@ -39,9 +38,9 @@ class BaseAction:
|
||||
def _import(self, *packages):
|
||||
return f'from jarvis.{".".join(packages)} import *'
|
||||
|
||||
@property
|
||||
def _command(self):
|
||||
raise NotImplementedError
|
||||
# @property
|
||||
# def _command(self):
|
||||
# raise NotImplementedError
|
||||
|
||||
@property
|
||||
def timeout(self):
|
||||
|
||||
@@ -7,20 +7,18 @@ action = execute_sql()
|
||||
action.run(db_path='../tasks/travel/database/travel.db', query='PRAGMA table_info(railway)')
|
||||
"""
|
||||
|
||||
class execute_sql(BaseAction):
|
||||
|
||||
class ExecuteSQL(BaseAction):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self._description = "Using turn_on_light_mode() will change your system into the light mode."
|
||||
|
||||
@property
|
||||
def _command(self):
|
||||
return self._python(_COMMAND)
|
||||
|
||||
|
||||
def run(self, db_path: str, query: str):
|
||||
def __call__(self, query: str = 'PRAGMA table_info(railway)'):
|
||||
if not query:
|
||||
return "No query, return"
|
||||
import sqlite3
|
||||
|
||||
conn = sqlite3.connect(db_path)
|
||||
conn = sqlite3.connect('../../tasks/travel/database/travel.db')
|
||||
cursor = conn.cursor()
|
||||
results = {
|
||||
"query": query,
|
||||
@@ -36,6 +34,11 @@ class execute_sql(BaseAction):
|
||||
conn.close()
|
||||
|
||||
return results
|
||||
|
||||
# @property
|
||||
# def _command(self):
|
||||
# return self._python(_COMMAND)
|
||||
|
||||
# def _success(self):
|
||||
# return "Successfully turned the system into the Light Mode"
|
||||
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
from jarvis.action.base_action import BaseAction
|
||||
|
||||
|
||||
class organize_app_layout(BaseAction):
|
||||
class OrgLayout(BaseAction):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self._description = "Using organize_app_layout() will help user reorganize their Desktop layout for better working condition and focus more easily."
|
||||
self._timeout = 15
|
||||
|
||||
@property
|
||||
def _command(self) -> str:
|
||||
def __call__(self, *args, **kwargs):
|
||||
return 'shortcuts run "Organize APP Layout"'
|
||||
|
||||
# @property
|
||||
# def _command(self) -> str:
|
||||
# return 'shortcuts run "Organize APP Layout"'
|
||||
#
|
||||
# def _success(self) -> str:
|
||||
# return "Successfully organized the app's layout"
|
||||
|
||||
118
jarvis/action_lib/python_interpreter.py
Normal file
118
jarvis/action_lib/python_interpreter.py
Normal file
@@ -0,0 +1,118 @@
|
||||
import copy
|
||||
import io
|
||||
from contextlib import redirect_stdout
|
||||
from typing import Any, Optional
|
||||
|
||||
from jarvis.action.base_action import BaseAction
|
||||
from jarvis.core.schema import ActionReturn
|
||||
|
||||
|
||||
class GenericRuntime:
|
||||
GLOBAL_DICT = {}
|
||||
LOCAL_DICT = None
|
||||
HEADERS = []
|
||||
|
||||
def __init__(self):
|
||||
self._global_vars = copy.copy(self.GLOBAL_DICT)
|
||||
self._local_vars = copy.copy(
|
||||
self.LOCAL_DICT) if self.LOCAL_DICT else None
|
||||
|
||||
for c in self.HEADERS:
|
||||
self.exec_code(c)
|
||||
|
||||
def exec_code(self, code_piece: str) -> None:
|
||||
exec(code_piece, self._global_vars)
|
||||
|
||||
def eval_code(self, expr: str) -> Any:
|
||||
return eval(expr, self._global_vars)
|
||||
|
||||
|
||||
DEFAULT_DESCRIPTION = """用来执行Python代码。代码必须是一个函数,
|
||||
函数名必须得是 'solution',代码对应你的思考过程。代码实例格式如下:
|
||||
```python
|
||||
# import 依赖包
|
||||
import time
|
||||
def solution():
|
||||
# 初始化一些变量
|
||||
print("hello world!")
|
||||
# 步骤一
|
||||
#mid_variable = func(variable_names_with_real_meaning)
|
||||
# 步骤 x
|
||||
#mid_variable = func(mid_variable)
|
||||
# 最后结果
|
||||
#final_answer = func(mid_variable)
|
||||
return "return!"
|
||||
```"""
|
||||
|
||||
|
||||
class PythonInterpreter(BaseAction):
|
||||
"""A Python executor that can execute Python scripts.
|
||||
|
||||
Args:
|
||||
description (str): The description of the action. Defaults to
|
||||
DEFAULT_DESCRIPTION.
|
||||
answer_symbol (str, Optional): the answer symbol from LLM
|
||||
answer_expr (str, Optional): the answer function name of the Python
|
||||
script. Default to 'solution()'.
|
||||
answer_from_stdout (boolean): whether the execution results is from
|
||||
stdout.
|
||||
name (str, optional): The name of the action. If None, the name will
|
||||
be class nameDefaults to None.
|
||||
timeout (int): Upper bound of waiting time for Python script execution.
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
description: str = DEFAULT_DESCRIPTION,
|
||||
answer_symbol: Optional[str] = None,
|
||||
answer_expr: Optional[str] = 'solution()',
|
||||
answer_from_stdout: bool = False,
|
||||
name: Optional[str] = None,
|
||||
timeout: int = 20) -> None:
|
||||
super().__init__(description, name, timeout)
|
||||
|
||||
self.answer_symbol = answer_symbol
|
||||
self.answer_expr = answer_expr
|
||||
self.answer_from_stdout = answer_from_stdout
|
||||
|
||||
def __call__(self, command: str) -> ActionReturn:
|
||||
self.runtime = GenericRuntime()
|
||||
self._call(command)
|
||||
|
||||
def _call(self, command: str) -> ActionReturn:
|
||||
tool_return = ActionReturn(url=None, args=None, type=self.name)
|
||||
try:
|
||||
if '```python' in command:
|
||||
command = command.split('```python')[1].split('```')[0]
|
||||
elif '```' in command:
|
||||
command = command.split('```')[1].split('```')[0]
|
||||
tool_return.args = dict(text='```python\n' + command + '\n```')
|
||||
command = command.split('\n')
|
||||
|
||||
if self.answer_from_stdout:
|
||||
program_io = io.StringIO()
|
||||
with redirect_stdout(program_io):
|
||||
self.runtime.exec_code('\n'.join(command))
|
||||
program_io.seek(0)
|
||||
res = program_io.readlines()[-1]
|
||||
elif self.answer_symbol:
|
||||
self.runtime.exec_code('\n'.join(command))
|
||||
res = self.runtime._global_vars[self.answer_symbol]
|
||||
elif self.answer_expr:
|
||||
self.runtime.exec_code('\n'.join(command))
|
||||
res = self.runtime.eval_code(self.answer_expr)
|
||||
else:
|
||||
self.runtime.exec_code('\n'.join(command[:-1]))
|
||||
res = self.runtime.eval_code(command[-1])
|
||||
except Exception as e:
|
||||
tool_return.errmsg = repr(e)
|
||||
tool_return.type = self.name
|
||||
# tool_return.state = ActionStatusCode.API_ERROR
|
||||
return tool_return
|
||||
try:
|
||||
tool_return.result = dict(text=str(res))
|
||||
# tool_return.state = ActionStatusCode.SUCCESS
|
||||
except Exception as e:
|
||||
tool_return.errmsg = repr(e)
|
||||
tool_return.type = self.name
|
||||
# tool_return.state = ActionStatusCode.API_ERROR
|
||||
return tool_return
|
||||
@@ -1,14 +1,18 @@
|
||||
from jarvis.action.base_action import BaseAction
|
||||
|
||||
|
||||
class turn_on_dark_mode(BaseAction):
|
||||
class DarkMode(BaseAction):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self._description = "Using turn_on_dark_mode() will change your system into the dark mode."
|
||||
self.action_type = 'BASH'
|
||||
|
||||
@property
|
||||
def _command(self):
|
||||
def __call__(self, *args, **kwargs):
|
||||
return 'shortcuts run "Dark Mode"'
|
||||
|
||||
# @property
|
||||
# def _command(self):
|
||||
# return 'shortcuts run "Dark Mode"'
|
||||
# return self._python(
|
||||
# self._import("atom", "operations"),
|
||||
# "adjust_theme('Adwaita-dark')"
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
from jarvis.action.base_action import BaseAction
|
||||
|
||||
|
||||
class turn_on_light_mode(BaseAction):
|
||||
class LightMode(BaseAction):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self._description = "Using turn_on_light_mode() will change your system into the light mode."
|
||||
|
||||
@property
|
||||
def _command(self):
|
||||
def __call__(self, *args, **kwargs):
|
||||
return 'shortcuts run "Light Mode"'
|
||||
|
||||
# @property
|
||||
# def _command(self):
|
||||
# return 'shortcuts run "Light Mode"'
|
||||
# return self._python(
|
||||
# self._import("atom", "operations"),
|
||||
# "adjust_theme('Adwaita')"
|
||||
|
||||
@@ -30,7 +30,7 @@ class BaseAgent:
|
||||
class_name = file[:-3].split('/')[-1] # 去除.py后缀,获取类名
|
||||
module = importlib.import_module(class_name)
|
||||
tmp_obj = getattr(module, class_name)()
|
||||
self.action_lib.update({class_name: tmp_obj._command})
|
||||
self.action_lib.update({class_name: tmp_obj})
|
||||
self.action_lib_description.update({class_name: tmp_obj.description})
|
||||
|
||||
|
||||
@@ -39,4 +39,4 @@ if __name__ == '__main__':
|
||||
a.init_action_lib()
|
||||
for k,v in a.action_lib.items():
|
||||
print(k)
|
||||
print(v)
|
||||
print(v())
|
||||
@@ -1,7 +1,7 @@
|
||||
import json
|
||||
from jarvis.core.llms import OpenAI
|
||||
from jarvis.agent.base_agent import BaseAgent
|
||||
from jarvis.enviroment.base_env import BaseEnviroment
|
||||
from jarvis.enviroment.old_env import BaseEnviroment
|
||||
from jarvis.core.schema import EnvState
|
||||
|
||||
|
||||
|
||||
@@ -32,5 +32,6 @@ class ActionReturn:
|
||||
class EnvState:
|
||||
command: List[str] = field(default_factory=list)
|
||||
result: Optional[str] = None
|
||||
error: Optional[str] = None
|
||||
pwd: Optional[str] = None
|
||||
ls: Optional[str] = None
|
||||
56
jarvis/enviroment/bash_env.py
Normal file
56
jarvis/enviroment/bash_env.py
Normal file
@@ -0,0 +1,56 @@
|
||||
import subprocess
|
||||
import time
|
||||
import os
|
||||
from typing import Optional, Union, List
|
||||
from jarvis.core.schema import ActionReturn, ActionStatusCode, EnvState
|
||||
from jarvis.enviroment.env import Env
|
||||
|
||||
|
||||
class BashEnv(Env):
|
||||
"""Base class for all actions.
|
||||
|
||||
Args:
|
||||
description (str, optional): The description of the action. Defaults to
|
||||
None.
|
||||
name (str, optional): The name of the action. If None, the name will
|
||||
be class name. Defaults to None.
|
||||
"""
|
||||
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self._name: str = self.__class__.__name__
|
||||
|
||||
def step(self, _command) -> EnvState:
|
||||
self.env_state = EnvState(command=_command)
|
||||
_command += ' && pwd'
|
||||
try:
|
||||
results = subprocess.run([_command], capture_output=True, check=True, cwd=self.working_dir,
|
||||
text=True, shell=True, timeout=self.timeout)
|
||||
if results.stdout:
|
||||
stout = results.stdout.strip().split('\n')
|
||||
self.env_state.result = "\n".join(stout[:-1])
|
||||
self.observe(stout[-1])
|
||||
return self.env_state
|
||||
except subprocess.CalledProcessError as e:
|
||||
self.env_state.error = e.stderr
|
||||
except Exception as e:
|
||||
self.env_state.error = repr(e)
|
||||
self.observe(self.working_dir)
|
||||
return self.env_state
|
||||
|
||||
def reset(self):
|
||||
self.working_dir = os.path.abspath(os.path.join(__file__, "..", "..", "..", "working_dir"))
|
||||
|
||||
def observe(self, pwd):
|
||||
self.env_state.pwd = pwd
|
||||
self.working_dir = pwd
|
||||
self.env_state.ls = subprocess.run(['ls'], cwd=self.working_dir, capture_output=True, text=True).stdout
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
env = BashEnv()
|
||||
print(env.step("ls"))
|
||||
print(env.step("cd ../../"))
|
||||
print(env.step("gogo"))
|
||||
env.reset()
|
||||
print(env.step("sleep 3"))
|
||||
43
jarvis/enviroment/env.py
Normal file
43
jarvis/enviroment/env.py
Normal file
@@ -0,0 +1,43 @@
|
||||
import subprocess
|
||||
import time
|
||||
import os
|
||||
from typing import Optional, Union, List
|
||||
from jarvis.core.schema import ActionReturn, ActionStatusCode, EnvState
|
||||
|
||||
|
||||
class Env:
|
||||
"""Base class for all actions.
|
||||
|
||||
Args:
|
||||
description (str, optional): The description of the action. Defaults to
|
||||
None.
|
||||
name (str, optional): The name of the action. If None, the name will
|
||||
be class name. Defaults to None.
|
||||
"""
|
||||
|
||||
def __init__(self) -> None:
|
||||
self._name: str = self.__class__.__name__
|
||||
self.timeout: int = 2
|
||||
self.working_dir = os.path.abspath(os.path.join(__file__, "..", "..", "..", "working_dir"))
|
||||
self.env_state: EnvState | None = None
|
||||
|
||||
def step(self, _command) -> EnvState:
|
||||
raise NotImplementedError
|
||||
|
||||
def reset(self):
|
||||
raise NotImplementedError
|
||||
@property
|
||||
def name(self):
|
||||
return self._name
|
||||
|
||||
def __repr__(self):
|
||||
return f'{self.name}'
|
||||
|
||||
def __str__(self):
|
||||
return self.__repr__()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
env = Env()
|
||||
env.env_state = EnvState()
|
||||
result = env.observe()
|
||||
75
jarvis/enviroment/py_env.py
Normal file
75
jarvis/enviroment/py_env.py
Normal file
@@ -0,0 +1,75 @@
|
||||
import subprocess
|
||||
import time
|
||||
import os
|
||||
from typing import Optional, Union, List
|
||||
from jarvis.core.schema import ActionReturn, ActionStatusCode, EnvState
|
||||
from jarvis.enviroment.env import Env
|
||||
from tempfile import NamedTemporaryFile
|
||||
|
||||
|
||||
class PythonEnv(Env):
|
||||
"""Base class for all actions.
|
||||
|
||||
Args:
|
||||
description (str, optional): The description of the action. Defaults to
|
||||
None.
|
||||
name (str, optional): The name of the action. If None, the name will
|
||||
be class name. Defaults to None.
|
||||
"""
|
||||
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self._name: str = self.__class__.__name__
|
||||
|
||||
def step(self, _command: str, args: list[str] | str = []) -> EnvState:
|
||||
|
||||
tmp_code_file = NamedTemporaryFile("w", dir=self.working_dir, suffix=".py", encoding="utf-8")
|
||||
tmp_code_file.write(_command)
|
||||
tmp_code_file.flush()
|
||||
filename = tmp_code_file.name
|
||||
if isinstance(args, str):
|
||||
args = args.split() # Convert space-separated string to a list
|
||||
self.env_state = EnvState(command=_command)
|
||||
try:
|
||||
results = subprocess.run(
|
||||
["python", '-B', str(filename)],
|
||||
encoding="utf8",
|
||||
check=True, cwd=self.working_dir, timeout=self.timeout,
|
||||
stdout=subprocess.PIPE
|
||||
)
|
||||
if results.stdout:
|
||||
stout = results.stdout.strip().split('\n')
|
||||
self.env_state.result = "\n".join(stout[:-1])
|
||||
self.observe(stout[-1])
|
||||
return self.env_state
|
||||
except subprocess.CalledProcessError as e:
|
||||
self.env_state.error = e.stderr
|
||||
except Exception as e:
|
||||
self.env_state.error = repr(e)
|
||||
finally:
|
||||
tmp_code_file.close()
|
||||
self.observe(self.working_dir)
|
||||
|
||||
return self.env_state
|
||||
|
||||
def reset(self):
|
||||
self.working_dir = os.path.abspath(os.path.join(__file__, "..", "..", "..", "working_dir"))
|
||||
|
||||
def observe(self, pwd):
|
||||
self.env_state.pwd = pwd
|
||||
self.working_dir = pwd
|
||||
self.env_state.ls = subprocess.run(['ls'], cwd=self.working_dir, capture_output=True, text=True).stdout
|
||||
|
||||
|
||||
DEFAULT_DESCRIPTION = """def solution():
|
||||
print("hello world!")
|
||||
print("hello world!")
|
||||
return "return!"
|
||||
"""
|
||||
if __name__ == '__main__':
|
||||
env = PythonEnv()
|
||||
print(env.step(DEFAULT_DESCRIPTION))
|
||||
# print(env.step("cd ../../"))
|
||||
# print(env.step("gogo"))
|
||||
# env.reset()
|
||||
# print(env.step("sleep 3"))
|
||||
Reference in New Issue
Block a user