Add linux_admin agent, funny~
This commit is contained in:
@@ -7,12 +7,11 @@ max_token_size = 16000
|
|||||||
enable_timestamp = "true"
|
enable_timestamp = "true"
|
||||||
owner_prompt = "我是你的主人{name}"
|
owner_prompt = "我是你的主人{name}"
|
||||||
contact_prompt = "我是你的朋友{name}"
|
contact_prompt = "我是你的朋友{name}"
|
||||||
guest_prompt = "xxx"
|
owner_env = "calender"
|
||||||
|
|
||||||
[[prompt]]
|
[[prompt]]
|
||||||
role = "system"
|
role = "system"
|
||||||
content = """
|
content = """
|
||||||
现在是{now}
|
|
||||||
你叫Jarvis,是我的超级私人助理。
|
你叫Jarvis,是我的超级私人助理。
|
||||||
你领导一个团队为我服务,团队的成员有:
|
你领导一个团队为我服务,团队的成员有:
|
||||||
Tracy,私人英语老师
|
Tracy,私人英语老师
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
instance_id = "linux_admin"
|
instance_id = "linux_admin"
|
||||||
fullname = "linux_admin"
|
fullname = "linux_admin"
|
||||||
|
owner_env = "bash"
|
||||||
[[prompt]]
|
[[prompt]]
|
||||||
role = "system"
|
role = "system"
|
||||||
content = """你的名字是linux_admin,是非常资深的linux系统管理员,我理解一些linux,但对linux的sh命令记得不太清楚了。
|
content = """你的名字是linux_admin,是非常资深的linux系统管理员,我理解一些linux,但对linux的sh命令记得不太清楚了。
|
||||||
我给你的输入有两种
|
我给你的输入有两种
|
||||||
1. 标准的linux bash命令,如果你认为这些命令在当前系统上是正确的,那么直接返回这些命令,我会去执行
|
1. 标准的linux bash命令,如果你认为这些命令在当前系统上是正确且可执行的,那么你可以直接执行
|
||||||
2. 如果你为这些命令需要调整后才能执行,先把你修正后的命令告诉我,我确认后再执行
|
2. 如果我的命令不对,或则命令可能对系统有害,你要对这些命令进行调整后,先把你调整后的命令告诉我,我确认后你再执行正确的命令
|
||||||
3. 如果我给你的信息不是linux bash操作,而是一些需求。你可以尝试理解后,给出一组实现这些需求的命令,我确认后再执行
|
3. 如果我给你的信息不是linux bash操作,而是一些需求。你可以尝试理解后,给出一组实现这些需求的命令,我确认后再执行
|
||||||
4. 其它信息,请站在你专业角度尽力执行。
|
4. 其它信息,请站在你专业角度尽力执行。
|
||||||
|
5. 每次执行命令后,要把结果告诉我。
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ from .tg_tunnel import TelegramTunnel
|
|||||||
from .email_tunnel import EmailTunnel
|
from .email_tunnel import EmailTunnel
|
||||||
from .storage import ResourceLocation,AIStorage,UserConfig,UserConfigItem
|
from .storage import ResourceLocation,AIStorage,UserConfig,UserConfigItem
|
||||||
from .contact_manager import ContactManager,Contact,FamilyMember
|
from .contact_manager import ContactManager,Contact,FamilyMember
|
||||||
|
from .workspace_env import WorkspaceEnvironment
|
||||||
|
|
||||||
AIOS_Version = "0.5.1, build 2023-9-17"
|
AIOS_Version = "0.5.1, build 2023-9-17"
|
||||||
|
|
||||||
|
|||||||
@@ -162,6 +162,8 @@ class AIAgent:
|
|||||||
if config.get("contact_prompt") is not None:
|
if config.get("contact_prompt") is not None:
|
||||||
self.contact_prompt_str = config["contact_prompt"]
|
self.contact_prompt_str = config["contact_prompt"]
|
||||||
|
|
||||||
|
if config.get("owner_env") is not None:
|
||||||
|
self.owner_env = Environment.get_env_by_id(config["owner_env"])
|
||||||
|
|
||||||
if config.get("powerby") is not None:
|
if config.get("powerby") is not None:
|
||||||
self.powerby = config["powerby"]
|
self.powerby = config["powerby"]
|
||||||
|
|||||||
@@ -4,11 +4,7 @@ import asyncio
|
|||||||
import uuid
|
import uuid
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from typing import Callable
|
from telegram import Update
|
||||||
|
|
||||||
from telegram import ForceReply, Update
|
|
||||||
from telegram.ext import Application, CommandHandler, ContextTypes, MessageHandler, filters
|
|
||||||
|
|
||||||
from telegram import Bot
|
from telegram import Bot
|
||||||
from telegram.ext import Updater
|
from telegram.ext import Updater
|
||||||
from telegram.error import Forbidden, NetworkError
|
from telegram.error import Forbidden, NetworkError
|
||||||
|
|||||||
@@ -1,2 +0,0 @@
|
|||||||
# this env is designed for workflow owner filesystem, support file/directory operations
|
|
||||||
|
|
||||||
@@ -0,0 +1,173 @@
|
|||||||
|
# this env is designed for workflow owner filesystem, support file/directory operations
|
||||||
|
|
||||||
|
import subprocess
|
||||||
|
import tempfile
|
||||||
|
import threading
|
||||||
|
import traceback
|
||||||
|
import time
|
||||||
|
import ast
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
|
||||||
|
from .environment import Environment,EnvironmentEvent
|
||||||
|
from .ai_function import AIFunction,SimpleAIFunction
|
||||||
|
|
||||||
|
|
||||||
|
class CodeInterpreter:
|
||||||
|
def __init__(self, language, debug_mode):
|
||||||
|
self.language = language
|
||||||
|
self.proc = None
|
||||||
|
self.active_line = None
|
||||||
|
self.debug_mode = debug_mode
|
||||||
|
|
||||||
|
def start_process(self):
|
||||||
|
start_cmd = sys.executable + " -i -q -u"
|
||||||
|
self.proc = subprocess.Popen(start_cmd.split(),
|
||||||
|
stdin=subprocess.PIPE,
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.PIPE,
|
||||||
|
text=True,
|
||||||
|
bufsize=0)
|
||||||
|
|
||||||
|
# Start watching ^ its `stdout` and `stderr` streams
|
||||||
|
threading.Thread(target=self.save_and_display_stream,
|
||||||
|
args=(self.proc.stdout, False), # Passes False to is_error_stream
|
||||||
|
daemon=True).start()
|
||||||
|
threading.Thread(target=self.save_and_display_stream,
|
||||||
|
args=(self.proc.stderr, True), # Passes True to is_error_stream
|
||||||
|
daemon=True).start()
|
||||||
|
|
||||||
|
def warp_code(self,pycode:str)->str:
|
||||||
|
# Add import traceback
|
||||||
|
code = "import traceback\n" + pycode
|
||||||
|
# Parse the input code into an AST
|
||||||
|
parsed_code = ast.parse(code)
|
||||||
|
# Wrap the entire code's AST in a single try-except block
|
||||||
|
try_except = ast.Try(
|
||||||
|
body=parsed_code.body,
|
||||||
|
handlers=[
|
||||||
|
ast.ExceptHandler(
|
||||||
|
type=ast.Name(id="Exception", ctx=ast.Load()),
|
||||||
|
name=None,
|
||||||
|
body=[
|
||||||
|
ast.Expr(
|
||||||
|
value=ast.Call(
|
||||||
|
func=ast.Attribute(value=ast.Name(id="traceback", ctx=ast.Load()), attr="print_exc", ctx=ast.Load()),
|
||||||
|
args=[],
|
||||||
|
keywords=[]
|
||||||
|
)
|
||||||
|
),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
],
|
||||||
|
orelse=[],
|
||||||
|
finalbody=[]
|
||||||
|
)
|
||||||
|
|
||||||
|
parsed_code.body = [try_except]
|
||||||
|
return ast.unparse(parsed_code)
|
||||||
|
|
||||||
|
def run(self,py_code:str):
|
||||||
|
"""
|
||||||
|
Executes code.
|
||||||
|
"""
|
||||||
|
# Get code to execute
|
||||||
|
self.code = py_code
|
||||||
|
|
||||||
|
# Start the subprocess if it hasn't been started
|
||||||
|
if not self.proc:
|
||||||
|
try:
|
||||||
|
self.start_process()
|
||||||
|
except Exception as e:
|
||||||
|
# Sometimes start_process will fail!
|
||||||
|
# Like if they don't have `node` installed or something.
|
||||||
|
|
||||||
|
traceback_string = traceback.format_exc()
|
||||||
|
self.output = traceback_string
|
||||||
|
# Before you return, wait for the display to catch up?
|
||||||
|
# (I'm not sure why this works)
|
||||||
|
time.sleep(0.1)
|
||||||
|
|
||||||
|
return self.output
|
||||||
|
|
||||||
|
self.output = ""
|
||||||
|
|
||||||
|
self.print_cmd = 'print("{}")'
|
||||||
|
code = self.warp_code(py_code)
|
||||||
|
|
||||||
|
if self.debug_mode:
|
||||||
|
print("Running code:")
|
||||||
|
print(code)
|
||||||
|
print("---")
|
||||||
|
|
||||||
|
self.done = threading.Event()
|
||||||
|
self.done.clear()
|
||||||
|
|
||||||
|
# Write code to stdin of the process
|
||||||
|
try:
|
||||||
|
self.proc.stdin.write(code + "\n")
|
||||||
|
self.proc.stdin.flush()
|
||||||
|
except BrokenPipeError:
|
||||||
|
return
|
||||||
|
self.done.wait()
|
||||||
|
time.sleep(0.1)
|
||||||
|
return self.output
|
||||||
|
|
||||||
|
def save_and_display_stream(self, stream, is_error_stream):
|
||||||
|
|
||||||
|
for line in iter(stream.readline, ''):
|
||||||
|
if self.debug_mode:
|
||||||
|
print("Recieved output line:")
|
||||||
|
print(line)
|
||||||
|
print("---")
|
||||||
|
|
||||||
|
line = line.strip()
|
||||||
|
if is_error_stream and "KeyboardInterrupt" in line:
|
||||||
|
raise KeyboardInterrupt
|
||||||
|
elif "END_OF_EXECUTION" in line:
|
||||||
|
self.done.set()
|
||||||
|
self.active_line = None
|
||||||
|
else:
|
||||||
|
self.output += "\n" + line
|
||||||
|
self.output = self.output.strip()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class WorkspaceEnvironment(Environment):
|
||||||
|
def __init__(self, env_id: str) -> None:
|
||||||
|
super().__init__(env_id)
|
||||||
|
|
||||||
|
operator_param = {
|
||||||
|
"command": "command will execute",
|
||||||
|
}
|
||||||
|
self.add_ai_function(SimpleAIFunction("shell_exec",
|
||||||
|
"execute shell command in linux bash",
|
||||||
|
self.shell_exec,operator_param))
|
||||||
|
|
||||||
|
#run_code_param = {
|
||||||
|
# "pycode": "python code will execute",
|
||||||
|
#}
|
||||||
|
#self.add_ai_function(SimpleAIFunction("run_code",
|
||||||
|
# "execute python code",
|
||||||
|
# self.run_code,run_code_param))
|
||||||
|
|
||||||
|
|
||||||
|
async def shell_exec(self,command:str) -> str:
|
||||||
|
import asyncio.subprocess
|
||||||
|
process = await asyncio.create_subprocess_shell(
|
||||||
|
command,
|
||||||
|
stdout=asyncio.subprocess.PIPE,
|
||||||
|
stderr=asyncio.subprocess.PIPE
|
||||||
|
)
|
||||||
|
stdout, stderr = await process.communicate()
|
||||||
|
returncode = process.returncode
|
||||||
|
if returncode == 0:
|
||||||
|
return f"Execute success! stdout is:\n{stdout}\n"
|
||||||
|
else:
|
||||||
|
return f"Execute failed! stderr is:\n{stderr}\n"
|
||||||
|
|
||||||
|
async def run_code(self,pycode:str) -> str:
|
||||||
|
interpreter = CodeInterpreter("python",True)
|
||||||
|
return interpreter.run(pycode)
|
||||||
|
|
||||||
@@ -64,7 +64,6 @@ class AIOS_Shell:
|
|||||||
target_id = msg.target.split(".")[0]
|
target_id = msg.target.split(".")[0]
|
||||||
agent : AIAgent = await AgentManager.get_instance().get(target_id)
|
agent : AIAgent = await AgentManager.get_instance().get(target_id)
|
||||||
if agent is not None:
|
if agent is not None:
|
||||||
agent.owner_env = Environment.get_env_by_id("calender")
|
|
||||||
bus.register_message_handler(target_id,agent._process_msg)
|
bus.register_message_handler(target_id,agent._process_msg)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -87,6 +86,9 @@ class AIOS_Shell:
|
|||||||
await cal_env.start()
|
await cal_env.start()
|
||||||
Environment.set_env_by_id("calender",cal_env)
|
Environment.set_env_by_id("calender",cal_env)
|
||||||
|
|
||||||
|
workspace_env = WorkspaceEnvironment("bash")
|
||||||
|
Environment.set_env_by_id("bash",workspace_env)
|
||||||
|
|
||||||
|
|
||||||
await AgentManager.get_instance().initial()
|
await AgentManager.get_instance().initial()
|
||||||
await WorkflowManager.get_instance().initial()
|
await WorkflowManager.get_instance().initial()
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import unittest
|
import unittest
|
||||||
import os
|
|
||||||
import toml
|
import toml
|
||||||
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
directory = os.path.dirname(__file__)
|
directory = os.path.dirname(__file__)
|
||||||
|
|||||||
+20
-2
@@ -1,9 +1,22 @@
|
|||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import asyncio
|
||||||
|
|
||||||
|
directory = os.path.dirname(__file__)
|
||||||
|
sys.path.append(directory + '/../src')
|
||||||
|
from aios_kernel import WorkspaceEnvironment
|
||||||
|
|
||||||
def test_workflow():
|
async def test_workflow():
|
||||||
|
env = WorkspaceEnvironment("test")
|
||||||
|
|
||||||
|
test_code ="""
|
||||||
|
import toml
|
||||||
|
print("hello world")
|
||||||
|
print(100+23)
|
||||||
|
toml.dump({"abc":"123"},open("test.toml","w"))
|
||||||
|
"""
|
||||||
|
await env.run_code(test_code)
|
||||||
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
async def _test_llm_parser():
|
async def _test_llm_parser():
|
||||||
@@ -40,3 +53,8 @@ sfsadfasdf
|
|||||||
assert len(llm_result.calls) == 1
|
assert len(llm_result.calls) == 1
|
||||||
assert len(llm_result.send_msgs) == 1
|
assert len(llm_result.send_msgs) == 1
|
||||||
print(llm_result)
|
print(llm_result)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
asyncio.run(test_workflow())
|
||||||
|
print("OK!")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user