1.Can use aios_shell from new jarvis telgram bot right now
2.Update MVP plan2.md 3.Refactor function support
This commit is contained in:
@@ -1,25 +1,62 @@
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import Dict
|
||||
|
||||
class AIFunction:
|
||||
def __init__(self) -> None:
|
||||
self.intro : str = None
|
||||
|
||||
def load_from_config(self,config:dict) -> bool:
|
||||
@abstractmethod
|
||||
def get_name(self) -> str:
|
||||
"""
|
||||
return the name of the function (should be snake case)
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_description(self) -> str:
|
||||
"""
|
||||
return a detailed description of what the function does
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def get_parameters(self) -> Dict:
|
||||
"""
|
||||
Return the list of parameters to execute this function in the form of
|
||||
JSON schema as specified in the OpenAI documentation:
|
||||
https://platform.openai.com/docs/api-reference/chat/create#chat/create-parameters
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def execute(self, **kwargs) -> Dict:
|
||||
"""
|
||||
Execute the function and return a JSON serializable dict.
|
||||
The parameters are passed in the form of kwargs
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def is_local(self) -> bool:
|
||||
"""
|
||||
is this function call need network?
|
||||
"""
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def is_in_zone(self) -> bool:
|
||||
pass
|
||||
|
||||
def is_readyonly(self) -> bool:
|
||||
"""
|
||||
is this function call in Lan?
|
||||
"""
|
||||
pass
|
||||
|
||||
def get_intro(self) -> str:
|
||||
return self.intro
|
||||
|
||||
async def execute(self):
|
||||
@abstractmethod
|
||||
def is_ready_only(self) -> bool:
|
||||
pass
|
||||
|
||||
#def load_from_config(self,config:dict) -> bool:
|
||||
# pass
|
||||
|
||||
# call chain is a combination of ai_function,group of ai_function.
|
||||
class CallChain:
|
||||
def __init__(self) -> None:
|
||||
|
||||
@@ -48,6 +48,12 @@ class Environment:
|
||||
def _do_get_value(self,key:str) -> Optional[str]:
|
||||
pass
|
||||
|
||||
def get_functions(self):
|
||||
# system functions
|
||||
# env functions
|
||||
# user install functions
|
||||
pass
|
||||
|
||||
def register_get_handler(self,key:str,handler:Callable) -> None:
|
||||
h = self.get_handlers.get(key)
|
||||
if h is not None:
|
||||
@@ -78,7 +84,7 @@ class Environment:
|
||||
for handler in handler_list:
|
||||
await handler(self.env_id,event)
|
||||
else:
|
||||
logger.warn(f"fire event {event_id} in env {self.env_id}:handler not found")
|
||||
logger.debug(f"fire event {event_id} in env {self.env_id}:handler not found")
|
||||
return
|
||||
|
||||
def __getitem__(self, key):
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
import logging
|
||||
import asyncio
|
||||
import json
|
||||
@@ -412,7 +411,10 @@ class Workflow:
|
||||
|
||||
|
||||
def _get_function_prompt(self,role_name:str) -> AgentPrompt:
|
||||
pass
|
||||
# system functions
|
||||
# env functions
|
||||
# user install functions
|
||||
pass
|
||||
|
||||
def _get_knowlege_prompt(self,role_name:str) -> AgentPrompt:
|
||||
pass
|
||||
|
||||
@@ -134,3 +134,6 @@ class WorkflowEnvironment(Environment):
|
||||
except Error as e:
|
||||
logging.error(f"Error occurred while update env{self.env_id}.{key} ,error:{e}")
|
||||
|
||||
def get_functions(self):
|
||||
pass
|
||||
|
||||
|
||||
@@ -0,0 +1,223 @@
|
||||
|
||||
import asyncio
|
||||
import sys
|
||||
import os
|
||||
import logging
|
||||
import re
|
||||
|
||||
from typing import Any, Optional, TypeVar, Tuple, Sequence
|
||||
import argparse
|
||||
|
||||
from telegram import ForceReply, Update
|
||||
from telegram.ext import Application, CommandHandler, ContextTypes, MessageHandler, filters
|
||||
|
||||
|
||||
directory = os.path.dirname(__file__)
|
||||
sys.path.append(directory + '/../../')
|
||||
from aios_kernel import Workflow,AIAgent,AgentMsg,AgentMsgState,ComputeKernel,OpenAI_ComputeNode,AIBus,AIChatSession
|
||||
|
||||
sys.path.append(directory + '/../../component/')
|
||||
from agent_manager import AgentManager
|
||||
from workflow_manager import WorkflowManager
|
||||
from aios_kernel import CalenderEnvironment,Environment
|
||||
|
||||
import logging
|
||||
|
||||
# Enable logging
|
||||
logging.basicConfig(
|
||||
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", level=logging.INFO
|
||||
)
|
||||
# set higher logging level for httpx to avoid all GET and POST requests being logged
|
||||
logging.getLogger("httpx").setLevel(logging.WARNING)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class AIOS_Shell:
|
||||
def __init__(self,username:str) -> None:
|
||||
self.username = username
|
||||
self.current_target = "_"
|
||||
self.current_topic = "default"
|
||||
|
||||
async def _handle_no_target_msg(self,bus:AIBus,msg:AgentMsg) -> bool:
|
||||
target_id = msg.target.split(".")[0]
|
||||
agent : AIAgent = await AgentManager().get(target_id)
|
||||
if agent is not None:
|
||||
bus.register_message_handler(target_id,agent._process_msg)
|
||||
return True
|
||||
|
||||
a_workflow = await WorkflowManager().get_workflow(target_id)
|
||||
if a_workflow is not None:
|
||||
bus.register_message_handler(target_id,a_workflow._process_msg)
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
async def is_agent(self,target_id:str) -> bool:
|
||||
agent : AIAgent = await AgentManager().get(target_id)
|
||||
if agent is not None:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
async def initial(self) -> bool:
|
||||
cal_env = CalenderEnvironment("calender")
|
||||
cal_env.start()
|
||||
Environment.set_env_by_id("calender",cal_env)
|
||||
|
||||
AgentManager().initial(os.path.abspath(directory + "/../../../rootfs/"))
|
||||
WorkflowManager().initial(os.path.abspath(directory + "/../../../rootfs/workflows/"))
|
||||
open_ai_node = OpenAI_ComputeNode()
|
||||
open_ai_node.start()
|
||||
ComputeKernel().add_compute_node(open_ai_node)
|
||||
AIBus().get_default_bus().register_unhandle_message_handler(self._handle_no_target_msg)
|
||||
return True
|
||||
|
||||
|
||||
def get_version(self) -> str:
|
||||
return "0.0.1"
|
||||
|
||||
async def send_msg(self,msg:str,target_id:str,topic:str,sender:str = None) -> str:
|
||||
agent_msg = AgentMsg()
|
||||
agent_msg.set(sender,target_id,msg)
|
||||
agent_msg.topic = topic
|
||||
resp = await AIBus.get_default_bus().send_message(target_id,agent_msg)
|
||||
if resp is not None:
|
||||
return resp.body
|
||||
else:
|
||||
return "error!"
|
||||
|
||||
async def install_workflow(self,workflow_id:Workflow) -> None:
|
||||
pass
|
||||
|
||||
async def call_func(self,func_name, args):
|
||||
match func_name:
|
||||
case 'send':
|
||||
target_id = args[0]
|
||||
msg_content = args[1]
|
||||
topic = args[2]
|
||||
resp = await self.send_msg(msg_content,target_id,topic,self.username)
|
||||
|
||||
|
||||
return resp
|
||||
case 'open':
|
||||
if len(args) >= 1:
|
||||
target_id = args[0]
|
||||
if len(args) >= 2:
|
||||
topic = args[1]
|
||||
|
||||
self.current_target = target_id
|
||||
self.current_topic = topic
|
||||
show_text = f"current session switch to {topic}@{target_id}"
|
||||
return show_text
|
||||
|
||||
|
||||
case 'history':
|
||||
num = 10
|
||||
offset = 0
|
||||
if args is not None:
|
||||
if len(args) >= 1:
|
||||
num = args[0]
|
||||
if len(args) >= 2:
|
||||
offset = args[1]
|
||||
|
||||
db_path = ""
|
||||
if await self.is_agent(self.current_target):
|
||||
db_path = AgentManager().db_path
|
||||
else:
|
||||
db_path = WorkflowManager().db_file
|
||||
chatsession:AIChatSession = AIChatSession.get_session(self.current_target,f"{self.username}#{self.current_topic}",db_path,False)
|
||||
if chatsession is not None:
|
||||
msgs = chatsession.read_history(num,offset)
|
||||
result_str = ""
|
||||
for msg in reversed(msgs):
|
||||
result_str += f"{msg.sender} >>> {msg.body}"
|
||||
result_str += f"\n-------------------\n"
|
||||
return result_str
|
||||
return f"chatsession not found"
|
||||
case 'help':
|
||||
return "help info "
|
||||
|
||||
shell:AIOS_Shell = None
|
||||
|
||||
async def _init_shell():
|
||||
global shell
|
||||
if shell is None:
|
||||
shell = AIOS_Shell("user")
|
||||
await shell.initial()
|
||||
return
|
||||
|
||||
def parse_function_call(func_string):
|
||||
match = re.search(r'\s*(\w+)\s*\(\s*(.*)\s*\)\s*', func_string)
|
||||
if not match:
|
||||
return None
|
||||
|
||||
func_name = match.group(1)
|
||||
params_string = match.group(2).strip()
|
||||
params = re.split(r'\s*,\s*(?=(?:[^"]*"[^"]*")*[^"]*$)', params_string)
|
||||
params = [param.strip('"') for param in params]
|
||||
if len(params[0]) == 0:
|
||||
params = None
|
||||
|
||||
return func_name, params
|
||||
|
||||
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
||||
"""Send a message when the command /start is issued."""
|
||||
await _init_shell()
|
||||
user = update.effective_user
|
||||
await update.message.reply_html(
|
||||
rf"Hi {user.mention_html()}!",
|
||||
reply_markup=ForceReply(selective=True),
|
||||
)
|
||||
|
||||
|
||||
async def on_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
||||
await _init_shell()
|
||||
cmd_msg = update.message.text[1:]
|
||||
logger.info("command:" + cmd_msg)
|
||||
func_call = parse_function_call(cmd_msg)
|
||||
if func_call:
|
||||
shell.username = update.effective_user
|
||||
show_text = await shell.call_func(func_call[0], func_call[1])
|
||||
await update.message.reply_text(show_text)
|
||||
else:
|
||||
await update.message.reply_text("command not found!")
|
||||
|
||||
async def on_message(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
||||
await _init_shell()
|
||||
shell.username = update.effective_user
|
||||
resp = await shell.send_msg(update.message.text,shell.current_target,shell.current_topic,shell.username)
|
||||
await update.message.reply_text(resp)
|
||||
|
||||
|
||||
|
||||
|
||||
def main() -> None:
|
||||
"""Start the bot."""
|
||||
# Create the Application and pass it your bot's token.
|
||||
tg_robot_token = os.getenv("TG_ROBOT_TOKEN")
|
||||
if tg_robot_token is None:
|
||||
print("TG_ROBOT_TOKEN not found!")
|
||||
tg_robot_token = input("input your telegram robot token:")
|
||||
|
||||
|
||||
if tg_robot_token is None:
|
||||
return
|
||||
|
||||
application = Application.builder().token(tg_robot_token).build()
|
||||
|
||||
# on different commands - answer in Telegram
|
||||
application.add_handler(CommandHandler("start", start))
|
||||
application.add_handler(CommandHandler("help", on_command))
|
||||
application.add_handler(CommandHandler("send", on_command))
|
||||
application.add_handler(CommandHandler("open", on_command))
|
||||
application.add_handler(CommandHandler("history", on_command))
|
||||
|
||||
# on non command i.e message - echo the message on Telegram
|
||||
application.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, on_message))
|
||||
|
||||
# Run the bot until the user presses Ctrl-C
|
||||
application.run_polling(allowed_updates=Update.ALL_TYPES)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user