Merge branch 'fiatrete:MVP' into MVP
This commit is contained in:
@@ -198,8 +198,6 @@ class AIAgent:
|
||||
if self.owner_env is None:
|
||||
return None
|
||||
|
||||
return None
|
||||
|
||||
all_inner_function = self.owner_env.get_all_ai_functions()
|
||||
if all_inner_function is None:
|
||||
return None
|
||||
@@ -219,15 +217,20 @@ class AIAgent:
|
||||
|
||||
func_name = inenr_func_call_node.get("name")
|
||||
arguments = json.loads(inenr_func_call_node.get("arguments"))
|
||||
logger.info(f"llm execute inner func:{func_name} ({json.dumps(arguments)})")
|
||||
|
||||
func_node : AIFunction = self.owner_env.get_ai_function(func_name)
|
||||
if func_node is None:
|
||||
return "execute failed,function not found"
|
||||
|
||||
ineternal_call_record = AgentMsg.create_internal_call_msg(func_name,arguments,org_msg.get_msg_id(),org_msg.target)
|
||||
try:
|
||||
result_str:str = await func_node.execute(**arguments)
|
||||
except Exception as e:
|
||||
result_str = "call error:" + str(e)
|
||||
logger.error(f"llm execute inner func:{func_name} error:{e}")
|
||||
|
||||
|
||||
result_str:str = await func_node.execute(**arguments)
|
||||
|
||||
inner_functions = self._get_inner_functions()
|
||||
prompt.messages.append({"role":"function","content":result_str,"name":func_name})
|
||||
task_result:ComputeTaskResult = await ComputeKernel.get_instance().do_llm_completion(prompt,self.llm_model_name,self.max_token_size,inner_functions)
|
||||
@@ -242,6 +245,17 @@ class AIAgent:
|
||||
else:
|
||||
return task_result.result_str
|
||||
|
||||
async def _get_agent_prompt(self) -> AgentPrompt:
|
||||
return self.prompt
|
||||
|
||||
def _format_msg_by_env_value(self,prompt:AgentPrompt):
|
||||
if self.owner_env is None:
|
||||
return
|
||||
|
||||
for msg in prompt.messages:
|
||||
old_content = msg.get("content")
|
||||
msg["content"] = old_content.format_map(self.owner_env)
|
||||
|
||||
async def _process_msg(self,msg:AgentMsg) -> AgentMsg:
|
||||
from .compute_kernel import ComputeKernel
|
||||
from .bus import AIBus
|
||||
@@ -255,7 +269,7 @@ class AIAgent:
|
||||
return None
|
||||
|
||||
prompt = AgentPrompt()
|
||||
prompt.append(self.prompt)
|
||||
prompt.append(await self._get_agent_prompt())
|
||||
# prompt.append(self._get_knowlege_prompt(the_role.get_name()))
|
||||
prompt.append(await self._get_prompt_from_session(chatsession)) # chat context
|
||||
|
||||
@@ -263,6 +277,7 @@ class AIAgent:
|
||||
msg_prompt.messages = [{"role":"user","content":msg.body}]
|
||||
prompt.append(msg_prompt)
|
||||
|
||||
self._format_msg_by_env_value(prompt)
|
||||
inner_functions = self._get_inner_functions()
|
||||
|
||||
task_result:ComputeTaskResult = await ComputeKernel.get_instance().do_llm_completion(prompt,self.llm_model_name,self.max_token_size,inner_functions)
|
||||
|
||||
@@ -35,7 +35,7 @@ class AgentMsgStatus(Enum):
|
||||
|
||||
class AgentMsg:
|
||||
def __init__(self,msg_type=AgentMsgType.TYPE_MSG) -> None:
|
||||
self.msg_id = ""
|
||||
self.msg_id = "msg#" + uuid.uuid4().hex
|
||||
self.msg_type:AgentMsgType = msg_type
|
||||
|
||||
self.prev_msg_id:str = None
|
||||
@@ -89,7 +89,6 @@ class AgentMsg:
|
||||
|
||||
def create_resp_msg(self,resp_body):
|
||||
resp_msg = AgentMsg()
|
||||
resp_msg.msg_id = "msg#" + uuid.uuid4().hex
|
||||
resp_msg.create_time = time.time()
|
||||
|
||||
resp_msg.rely_msg_id = self.msg_id
|
||||
@@ -101,7 +100,6 @@ class AgentMsg:
|
||||
return resp_msg
|
||||
|
||||
def set(self,sender:str,target:str,body:str,topic:str=None) -> None:
|
||||
self.msg_id = "msg#" + uuid.uuid4().hex
|
||||
self.sender = sender
|
||||
self.target = target
|
||||
self.body = body
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import Dict,Coroutine,Callable
|
||||
|
||||
class ParameterDefine:
|
||||
def __init__(self) -> None:
|
||||
self.name = None
|
||||
self.type = None
|
||||
self.description = None
|
||||
|
||||
|
||||
class AIFunction:
|
||||
def __init__(self) -> None:
|
||||
self.description : str = None
|
||||
@@ -107,9 +114,19 @@ class SimpleAIFunction(AIFunction):
|
||||
|
||||
def get_parameters(self) -> Dict:
|
||||
if self.parameters is not None:
|
||||
return self.parameters
|
||||
result = {}
|
||||
result["type"] = "object"
|
||||
parm_defines = {}
|
||||
for parm,desc in self.parameters.items():
|
||||
parm_item = {}
|
||||
parm_item["type"] = "string"
|
||||
parm_item["description"] = desc
|
||||
parm_defines[parm] = parm_item
|
||||
result["properties"] = parm_defines
|
||||
return result
|
||||
return {"type": "object", "properties": {}}
|
||||
|
||||
|
||||
async def execute(self,**kwargs) -> str:
|
||||
if self.func_handler is None:
|
||||
return "error: function not implemented"
|
||||
|
||||
@@ -167,8 +167,12 @@ class OpenAI_ComputeNode(ComputeNode):
|
||||
|
||||
def is_support(self, task: ComputeTask) -> bool:
|
||||
if task.task_type == ComputeTaskType.LLM_COMPLETION:
|
||||
if not task.params["model_name"] or task.params["model_name"] == "gpt-4-0613":
|
||||
if not task.params["model_name"]:
|
||||
return True
|
||||
model_name : str = task.params["model_name"]
|
||||
if model_name.startswith("gpt-"):
|
||||
return True
|
||||
|
||||
if task.task_type == ComputeTaskType.TEXT_EMBEDDING:
|
||||
if task.params["model_name"] == "text-embedding-ada-002":
|
||||
return True
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
|
||||
from datetime import datetime
|
||||
import asyncio
|
||||
import json
|
||||
import sqlite3 # Because sqlite3 IO operation is small, so we can use sqlite3 directly.(so we don't need to use async sqlite3 now)
|
||||
from sqlite3 import Error
|
||||
import threading
|
||||
@@ -8,6 +9,9 @@ import logging
|
||||
from typing import Optional
|
||||
from .environment import Environment,EnvironmentEvent
|
||||
from .ai_function import SimpleAIFunction
|
||||
from .storage import AIStorage
|
||||
|
||||
import aiosqlite
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -25,20 +29,187 @@ class CalenderEvent(EnvironmentEvent):
|
||||
class CalenderEnvironment(Environment):
|
||||
def __init__(self, env_id: str) -> None:
|
||||
super().__init__(env_id)
|
||||
self.db_file = AIStorage.get_instance().get_myai_dir() / "calender.db"
|
||||
self.is_run = False
|
||||
|
||||
self.add_ai_function(SimpleAIFunction("get_time",
|
||||
"get current time",
|
||||
self._get_now))
|
||||
|
||||
#self.add_ai_function(SimpleAIFunction("serach_events",
|
||||
# "search events in calender",
|
||||
# self._search_events))
|
||||
|
||||
get_param = {
|
||||
"start_time": "start time (UTC) of event",
|
||||
"end_time": "end time (UTC) of event"
|
||||
}
|
||||
self.add_ai_function(SimpleAIFunction("get_events",
|
||||
"get events in calender by time range",
|
||||
self._get_events_by_time_range,get_param))
|
||||
|
||||
add_param = {
|
||||
"title": "title of event",
|
||||
"start_time": "start time (UTC) of event",
|
||||
"end_time": "end time (UTC) of event",
|
||||
"participants": "participants of event",
|
||||
"location": "location of event",
|
||||
"details": "details of event"
|
||||
}
|
||||
self.add_ai_function(SimpleAIFunction("add_event",
|
||||
"add event to calender",
|
||||
self._add_event,add_param))
|
||||
|
||||
delete_param = {
|
||||
"event_id": "id of event"
|
||||
}
|
||||
self.add_ai_function(SimpleAIFunction("delete_event",
|
||||
"delete event from calender",
|
||||
self._delete_event,delete_param))
|
||||
|
||||
update_param = {
|
||||
"event_id": "id of event",
|
||||
"new_title": "new title of event",
|
||||
"new_participants": "new participants of event",
|
||||
"new_location": "new location of event",
|
||||
"new_details": "new details of event",
|
||||
"start_time": "new start time (UTC) of event",
|
||||
"end_time": "new end time (UTC) of event"
|
||||
}
|
||||
self.add_ai_function(SimpleAIFunction("update_event",
|
||||
"update event in calender",
|
||||
self._update_event,update_param))
|
||||
|
||||
#self.add_ai_function(SimpleAIFunction("user_confirm",
|
||||
# "user confirm",
|
||||
# self._user_confirm))
|
||||
|
||||
async def init_db(self):
|
||||
async with aiosqlite.connect(self.db_file) as db:
|
||||
await db.execute("""
|
||||
CREATE TABLE IF NOT EXISTS events (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
title TEXT,
|
||||
start_time DATETIME,
|
||||
end_time DATETIME,
|
||||
participants TEXT,
|
||||
location TEXT,
|
||||
details TEXT
|
||||
);
|
||||
""")
|
||||
await db.commit()
|
||||
|
||||
async def _add_event(self,title, start_time, end_time, participants=None, location=None, details=None):
|
||||
async with aiosqlite.connect(self.db_file) as db:
|
||||
await db.execute("""
|
||||
INSERT INTO events (title, start_time, end_time, participants, location, details)
|
||||
VALUES (?, ?, ?, ?, ?, ?);
|
||||
""", (title, start_time, end_time, participants, location, details))
|
||||
await db.commit()
|
||||
return "Add event ok"
|
||||
|
||||
async def _search_events(self,query):
|
||||
async with aiosqlite.connect(self.db_file) as db:
|
||||
cursor = await db.execute("""
|
||||
SELECT id,title, start_time, end_time, participants, location, details FROM events
|
||||
WHERE title LIKE ? OR participants LIKE ? OR location LIKE ? OR details LIKE ?;
|
||||
""", (f"%{query}%", f"%{query}%", f"%{query}%", f"%{query}%"))
|
||||
rows = await cursor.fetchall()
|
||||
|
||||
result = {}
|
||||
for row in rows:
|
||||
_event = {}
|
||||
_event["title"] = row[1]
|
||||
_event["start_time"] = row[2]
|
||||
_event["end_time"] = row[3]
|
||||
_event["participants"] = row[4]
|
||||
_event["location"] = row[5]
|
||||
_event["details"] = row[6]
|
||||
result[row[0]] = _event
|
||||
return json.dumps(result, indent=4, sort_keys=True)
|
||||
|
||||
async def _get_events_by_time_range(self,start_time, end_time):
|
||||
async with aiosqlite.connect(self.db_file) as db:
|
||||
cursor = await db.execute("""
|
||||
SELECT id,title, start_time, end_time, participants, location, details FROM events
|
||||
WHERE start_time >= ? AND end_time <= ?;
|
||||
""", (start_time, end_time))
|
||||
rows = await cursor.fetchall()
|
||||
|
||||
result = {}
|
||||
for row in rows:
|
||||
_event = {}
|
||||
_event["title"] = row[1]
|
||||
_event["start_time"] = row[2]
|
||||
_event["end_time"] = row[3]
|
||||
_event["participants"] = row[4]
|
||||
_event["location"] = row[5]
|
||||
_event["details"] = row[6]
|
||||
result[row[0]] = _event
|
||||
return json.dumps(result, indent=4, sort_keys=True)
|
||||
|
||||
async def _update_event(self,event_id, new_title=None, new_participants=None, new_location=None, new_details=None ,start_time=None, end_time=None):
|
||||
fields_to_update = []
|
||||
values = []
|
||||
|
||||
if new_title is not None:
|
||||
fields_to_update.append("title = ?")
|
||||
values.append(new_title)
|
||||
|
||||
if new_participants is not None:
|
||||
fields_to_update.append("participants = ?")
|
||||
values.append(new_participants)
|
||||
|
||||
if new_location is not None:
|
||||
fields_to_update.append("location = ?")
|
||||
values.append(new_location)
|
||||
|
||||
if new_details is not None:
|
||||
fields_to_update.append("details = ?")
|
||||
values.append(new_details)
|
||||
|
||||
if start_time is not None:
|
||||
fields_to_update.append("start_time = ?")
|
||||
values.append(start_time)
|
||||
|
||||
if end_time is not None:
|
||||
fields_to_update.append("end_time = ?")
|
||||
values.append(end_time)
|
||||
|
||||
if not fields_to_update:
|
||||
return "No fields to update."
|
||||
|
||||
sql_update_query = f"""
|
||||
UPDATE events
|
||||
SET {', '.join(fields_to_update)}
|
||||
WHERE id = ?;
|
||||
"""
|
||||
|
||||
values.append(event_id)
|
||||
|
||||
async with aiosqlite.connect(self.db_file) as db:
|
||||
await db.execute(sql_update_query, values)
|
||||
await db.commit()
|
||||
return "update ok"
|
||||
|
||||
async def _delete_event(self,event_id):
|
||||
async with aiosqlite.connect(self.db_file) as db:
|
||||
await db.execute("""
|
||||
DELETE FROM events
|
||||
WHERE id = ?;
|
||||
""", (event_id,))
|
||||
await db.commit()
|
||||
return "Delete event ok"
|
||||
|
||||
def _do_get_value(self,key:str) -> Optional[str]:
|
||||
return None
|
||||
|
||||
def start(self) -> None:
|
||||
async def start(self) -> None:
|
||||
if self.is_run:
|
||||
return
|
||||
self.is_run = True
|
||||
|
||||
await self.init_db()
|
||||
|
||||
self.register_get_handler("now",self.get_now)
|
||||
async def timer_loop():
|
||||
while True:
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
# this env is designed for workflow owner filesystem, support file/directory operations
|
||||
|
||||
|
||||
Reference in New Issue
Block a user