Merge branch 'new_infra_zy' of https://github.com/LividWo/jarvis into new_infra_zy

pull new_infra_zy
This commit is contained in:
hccngu
2023-11-14 19:48:52 +08:00
17 changed files with 398 additions and 39 deletions

View File

@@ -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

View File

@@ -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";')

View 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)

View File

@@ -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__':

View File

@@ -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):

View File

@@ -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"

View File

@@ -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"

View 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

View File

@@ -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')"

View File

@@ -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')"

View File

@@ -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())

View File

@@ -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

View File

@@ -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

View 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
View 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()

View 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"))