- main system prompt split
- history rework in progress
This commit is contained in:
frdel 2024-10-03 15:17:31 +02:00
parent d321635584
commit 7da114d286
20 changed files with 749 additions and 257 deletions

View file

@ -0,0 +1,37 @@
from datetime import datetime
from python.helpers.extension import Extension
from agent import Agent, LoopData
class SystemPrompt(Extension):
async def execute(self, loop_data: LoopData = LoopData(), **kwargs):
# collect and concatenate main prompts
main = concat_main_prompts(self.agent)
# collect and concatenate tool instructions
tools = concat_tool_prompts(self.agent)
# append to system message
loop_data.system.append(main)
loop_data.system.append(tools)
def concat_main_prompts(agent: Agent):
# variables for prompts
vars = {
"date_time": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
"agent_name": agent.agent_name,
}
# prompt files
mains = agent.read_prompts("agent.system.main.*.md", **vars)
mains = "\n\n".join(mains)
return mains
def concat_tool_prompts(agent: Agent):
# prompt files
tools = agent.read_prompts("agent.system.tool.*.md")
tools = "\n\n".join(tools)
# tools template
sys = agent.read_prompt("agent.system.tools.md", tools=tools)
return sys

View file

@ -1,23 +0,0 @@
from python.helpers.extension import Extension
from agent import Agent, LoopData
class RecallMemories(Extension):
INTERVAL = 3
HISTORY = 5
RESULTS = 3
THRESHOLD = 0.1
async def execute(self, loop_data: LoopData = LoopData(), **kwargs):
# collect and concatenate tool instructions
sys = concat_tool_prompts(self.agent)
# append to system message
loop_data.system.append(sys)
def concat_tool_prompts(agent: Agent):
tools = agent.read_prompts("agent.system.tool.*.md")
tools = "\n\n".join(tools)
sys = agent.read_prompt("agent.system.tools.md", tools=tools)
return sys

View file

@ -4,7 +4,7 @@ from typing import Literal, Optional, Dict
import uuid
type Type = Literal[
Type = Literal[
"agent",
"code_exe",
"error",

View file

@ -1,5 +1,5 @@
from datetime import datetime
from typing import Any
from typing import Any, List, Sequence
from langchain.storage import InMemoryByteStore, LocalFileStore
from langchain.embeddings import CacheBackedEmbeddings
@ -21,6 +21,14 @@ from python.helpers.log import Log, LogItem
from enum import Enum
from agent import Agent
class MyFaiss(FAISS):
#override aget_by_ids
def get_by_ids(self, ids: Sequence[str], /) -> List[Document]:
# return all self.docstore._dict[id] in ids
return [self.docstore._dict[id] for id in ids if id in self.docstore._dict] #type: ignore
async def aget_by_ids(self, ids: Sequence[str], /) -> List[Document]:
return self.get_by_ids(ids)
class Memory:
@ -28,7 +36,7 @@ class Memory:
MAIN = "main"
SOLUTIONS = "solutions"
index: dict[str, "FAISS"] = {}
index: dict[str, "MyFaiss"] = {}
@staticmethod
async def get(agent: Agent):
@ -64,7 +72,7 @@ class Memory:
embeddings_model,
memory_subdir: str,
in_memory=False,
):
) -> MyFaiss:
print("Initializing VectorDB...")
@ -102,7 +110,7 @@ class Memory:
# if db folder exists and is not empty:
if os.path.exists(db_dir) and files.exists(db_dir, "index.faiss"):
db = FAISS.load_local(
db = MyFaiss.load_local(
folder_path=db_dir,
embeddings=embedder,
allow_dangerous_deserialization=True,
@ -113,7 +121,7 @@ class Memory:
else:
index = faiss.IndexFlatIP(len(embedder.embed_query("example")))
db = FAISS(
db = MyFaiss(
embedding_function=embedder,
index=index,
docstore=InMemoryDocstore(),
@ -122,12 +130,12 @@ class Memory:
# normalize_L2=True,
relevance_score_fn=Memory._cosine_normalizer,
)
return db
return db # type: ignore
def __init__(
self,
agent: Agent,
db: FAISS,
db: MyFaiss,
memory_subdir: str,
):
self.agent = agent
@ -226,13 +234,15 @@ class Memory:
return removed
async def delete_documents_by_ids(self, ids: list[str]):
# pre = self.db.get(ids=ids)["ids"]
self.db.delete(ids=ids)
# post = self.db.get(ids=ids)["ids"]
# TODO? compare pre and post
if ids:
# aget_by_ids is not yet implemented in faiss, need to do a workaround
rem_docs =self.db.get_by_ids(ids) # existing docs to remove (prevents error)
if rem_docs:
rem_ids = [doc.metadata["id"] for doc in rem_docs] # ids to remove
await self.db.adelete(ids=rem_ids)
if rem_docs:
self._save_db() # persist
return len(ids)
return rem_docs
def insert_text(self, text, metadata: dict = {}):
id = str(uuid.uuid4())

View file

@ -7,5 +7,5 @@ class MemoryForget(Tool):
db = await Memory.get(self.agent)
dels = await db.delete_documents_by_ids(ids=ids)
result = self.agent.read_prompt("fw.memories_deleted.md", memory_count=dels)
result = self.agent.read_prompt("fw.memories_deleted.md", memory_count=len(dels))
return Response(message=result, break_loop=False)

View file

@ -1,92 +0,0 @@
import re
from agent import Agent
from python.helpers.vector_db import get_or_create_db, Area
import os
from python.helpers.tool import Tool, Response
from python.helpers.print_style import PrintStyle
from python.helpers.errors import handle_error
from python.helpers import files
DEFAULT_THRESHOLD = 0.5
class Memory(Tool):
async def execute(self, **kwargs):
result = ""
try:
if "query" in kwargs:
threshold = float(kwargs.get("threshold", DEFAULT_THRESHOLD))
count = int(kwargs.get("limit", 5))
result = search(self.agent, kwargs["query"], count, threshold)
elif "memorize" in kwargs:
meta = {"area": Area.MAIN.value}
result = save(self.agent, kwargs["memorize"])
elif "forget" in kwargs:
result = forget(self.agent, kwargs["forget"])
# elif "delete" in kwargs
result = delete(self.agent, kwargs["delete"])
except Exception as e:
handle_error(e)
# hint about embedding change with existing database
PrintStyle.hint(
"If you changed your embedding model, you will need to remove contents of /memory directory."
)
self.agent.context.log.log(
type="hint",
content="If you changed your embedding model, you will need to remove contents of /memory directory.",
)
raise
# result = process_query(self.agent, self.args["memory"],self.args["action"], result_count=self.agent.config.auto_memory_count)
return Response(message=result, break_loop=False)
def search(
agent: Agent, query: str, count: int = 5, threshold: float = DEFAULT_THRESHOLD
):
db = get_db(agent)
# docs = db.search_similarity(query,count) # type: ignore
docs = db.search_similarity_threshold(query=query, limit=count, threshold=threshold) # type: ignore
if len(docs) == 0:
return agent.read_prompt("fw.memories_not_found.md", query=query)
else:
return str(docs)
def save(agent: Agent, text: str, metadata: dict = {}):
db = get_db(agent)
id = db.insert_text(text, metadata) # type: ignore
return agent.read_prompt("fw.memory_saved.md", memory_id=id)
def delete(agent: Agent, ids_str: str):
db = get_db(agent)
ids = extract_guids(ids_str)
deleted = db.delete_documents_by_ids(ids) # type: ignore
return agent.read_prompt("fw.memories_deleted.md", memory_count=deleted)
def forget(agent: Agent, query: str):
db = get_db(agent)
deleted = db.delete_documents_by_query(query) # type: ignore
return agent.read_prompt("fw.memories_deleted.md", memory_count=deleted)
def get_db(agent: Agent):
mem_dir = files.get_abs_path("memory", agent.config.memory_subdir or "default")
kn_dirs = [
files.get_abs_path("knowledge", d) for d in agent.config.knowledge_subdirs or []
]
db = get_or_create_db(
agent=agent,
)
return db
def extract_guids(text):
pattern = r"\b[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-5][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}\b"
return re.findall(pattern, text)

View file

@ -1,5 +1,5 @@
from python.helpers.tool import Tool, Response
from python.extensions.message_loop_prompts._10_tool_instructions import (
from python.extensions.message_loop_prompts._10_system_prompt import (
concat_tool_prompts,
)