Spaces:
Paused
Paused
frdel commited on
Commit ·
c807769
1
Parent(s): 9910b5a
delayed memory recall
Browse files- README.md +1 -0
- prompts/memory.memories_query.sys.md +7 -0
- prompts/memory.memories_sum.sys.md +10 -2
- prompts/memory.recall_delay_msg.md +1 -0
- python/extensions/message_loop_prompts_after/_50_recall_memories.py +25 -14
- python/extensions/message_loop_prompts_after/_91_recall_wait.py +23 -10
- python/extensions/monologue_start/_10_memory_init.py +13 -0
- python/helpers/settings.py +13 -1
README.md
CHANGED
|
@@ -176,6 +176,7 @@ docker run -p 50001:80 agent0ai/agent-zero
|
|
| 176 |
- New notifications system
|
| 177 |
- New local terminal interface for stability
|
| 178 |
- Rate limiter integration to models
|
|
|
|
| 179 |
- Smarter autoscrolling in UI
|
| 180 |
- Action buttons in messages
|
| 181 |
- Multiple API keys support
|
|
|
|
| 176 |
- New notifications system
|
| 177 |
- New local terminal interface for stability
|
| 178 |
- Rate limiter integration to models
|
| 179 |
+
- Delayed memory recall
|
| 180 |
- Smarter autoscrolling in UI
|
| 181 |
- Action buttons in messages
|
| 182 |
- Multiple API keys support
|
prompts/memory.memories_query.sys.md
CHANGED
|
@@ -7,11 +7,18 @@
|
|
| 7 |
- The response format is a plain text string containing the query
|
| 8 |
- No other text, no formatting
|
| 9 |
|
|
|
|
|
|
|
|
|
|
| 10 |
# Rules
|
| 11 |
- Only focus on facts and events, ignore common conversation patterns, greeting etc.
|
| 12 |
- Ignore AI thoughts and behavior
|
| 13 |
- Focus on USER MESSAGE if provided, use HISTORY for context
|
| 14 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
# Example
|
| 16 |
```json
|
| 17 |
USER: "Write a song about my dog"
|
|
|
|
| 7 |
- The response format is a plain text string containing the query
|
| 8 |
- No other text, no formatting
|
| 9 |
|
| 10 |
+
# No query
|
| 11 |
+
- If the conversation is not relevant for memory search, return a single dash (-)
|
| 12 |
+
|
| 13 |
# Rules
|
| 14 |
- Only focus on facts and events, ignore common conversation patterns, greeting etc.
|
| 15 |
- Ignore AI thoughts and behavior
|
| 16 |
- Focus on USER MESSAGE if provided, use HISTORY for context
|
| 17 |
|
| 18 |
+
# Ignored:
|
| 19 |
+
For the following topics, no query is needed and return a single dash (-):
|
| 20 |
+
- Greeting
|
| 21 |
+
|
| 22 |
# Example
|
| 23 |
```json
|
| 24 |
USER: "Write a song about my dog"
|
prompts/memory.memories_sum.sys.md
CHANGED
|
@@ -36,10 +36,18 @@
|
|
| 36 |
> AsyncRaceError in primary_modules.py was fixed by adding a thread lock on line 123 (important event with details for context)
|
| 37 |
> Local SQL database was created, server is running on port 3306 (important event with details for context)
|
| 38 |
|
| 39 |
-
#
|
| 40 |
> Dog Information (no useful facts)
|
| 41 |
> User greeted with 'hi' (just conversation, not useful in the future )
|
| 42 |
> Respond with a warm greeting and invite further conversation (do not memorize AI's instructions or thoughts)
|
| 43 |
> User's name (details missing, not useful)
|
| 44 |
> Today is Monday (just date, no value in this information)
|
| 45 |
-
> Market inquiry (just a topic without detail)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 36 |
> AsyncRaceError in primary_modules.py was fixed by adding a thread lock on line 123 (important event with details for context)
|
| 37 |
> Local SQL database was created, server is running on port 3306 (important event with details for context)
|
| 38 |
|
| 39 |
+
# WRONG examples with (explanation of error), never output memories like these
|
| 40 |
> Dog Information (no useful facts)
|
| 41 |
> User greeted with 'hi' (just conversation, not useful in the future )
|
| 42 |
> Respond with a warm greeting and invite further conversation (do not memorize AI's instructions or thoughts)
|
| 43 |
> User's name (details missing, not useful)
|
| 44 |
> Today is Monday (just date, no value in this information)
|
| 45 |
+
> Market inquiry (just a topic without detail)
|
| 46 |
+
> RAM Status (just a topic without detail)
|
| 47 |
+
> The user requested current RAM and CPU status. (No exact facts to memorize)
|
| 48 |
+
|
| 49 |
+
|
| 50 |
+
# Further WRONG examples
|
| 51 |
+
- Hello
|
| 52 |
+
- The user requested current RAM and CPU status.
|
| 53 |
+
-
|
prompts/memory.recall_delay_msg.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
Info: auto memory recall set to delayed mode. auto memories will be available after next message. if manual memory check is required use memory tools.
|
python/extensions/message_loop_prompts_after/_50_recall_memories.py
CHANGED
|
@@ -3,9 +3,11 @@ from python.helpers.extension import Extension
|
|
| 3 |
from python.helpers.memory import Memory
|
| 4 |
from agent import LoopData
|
| 5 |
from python.tools.memory_load import DEFAULT_THRESHOLD as DEFAULT_MEMORY_THRESHOLD
|
| 6 |
-
from python.helpers import dirty_json, errors, settings
|
|
|
|
| 7 |
|
| 8 |
DATA_NAME_TASK = "_recall_memories_task"
|
|
|
|
| 9 |
|
| 10 |
|
| 11 |
class RecallMemories(Extension):
|
|
@@ -22,18 +24,30 @@ class RecallMemories(Extension):
|
|
| 22 |
|
| 23 |
set = settings.get_settings()
|
| 24 |
|
| 25 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
if loop_data.iteration % set["memory_recall_interval"] == 0:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 27 |
task = asyncio.create_task(
|
| 28 |
-
self.search_memories(loop_data=loop_data, **kwargs)
|
| 29 |
)
|
| 30 |
else:
|
| 31 |
task = None
|
| 32 |
|
| 33 |
# set to agent to be able to wait for it
|
| 34 |
self.agent.set_data(DATA_NAME_TASK, task)
|
|
|
|
| 35 |
|
| 36 |
-
async def search_memories(self, loop_data: LoopData, **kwargs):
|
| 37 |
|
| 38 |
# cleanup
|
| 39 |
extras = loop_data.extras_persistent
|
|
@@ -46,16 +60,6 @@ class RecallMemories(Extension):
|
|
| 46 |
set = settings.get_settings()
|
| 47 |
# try:
|
| 48 |
|
| 49 |
-
# if recall is disabled, return
|
| 50 |
-
if not set["memory_recall_enabled"]:
|
| 51 |
-
return
|
| 52 |
-
|
| 53 |
-
# show full util message
|
| 54 |
-
log_item = self.agent.context.log.log(
|
| 55 |
-
type="util",
|
| 56 |
-
heading="Searching memories...",
|
| 57 |
-
)
|
| 58 |
-
|
| 59 |
# get system message and chat history for util llm
|
| 60 |
system = self.agent.read_prompt("memory.memories_query.sys.md")
|
| 61 |
|
|
@@ -100,6 +104,13 @@ class RecallMemories(Extension):
|
|
| 100 |
else:
|
| 101 |
query = user_instruction + "\n\n" + history
|
| 102 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 103 |
# get memory database
|
| 104 |
db = await Memory.get(self.agent)
|
| 105 |
|
|
|
|
| 3 |
from python.helpers.memory import Memory
|
| 4 |
from agent import LoopData
|
| 5 |
from python.tools.memory_load import DEFAULT_THRESHOLD as DEFAULT_MEMORY_THRESHOLD
|
| 6 |
+
from python.helpers import dirty_json, errors, settings, log
|
| 7 |
+
|
| 8 |
|
| 9 |
DATA_NAME_TASK = "_recall_memories_task"
|
| 10 |
+
DATA_NAME_ITER = "_recall_memories_iter"
|
| 11 |
|
| 12 |
|
| 13 |
class RecallMemories(Extension):
|
|
|
|
| 24 |
|
| 25 |
set = settings.get_settings()
|
| 26 |
|
| 27 |
+
# turned off in settings?
|
| 28 |
+
if not set["memory_recall_enabled"]:
|
| 29 |
+
return
|
| 30 |
+
|
| 31 |
+
# every X iterations (or the first one) recall memories
|
| 32 |
if loop_data.iteration % set["memory_recall_interval"] == 0:
|
| 33 |
+
|
| 34 |
+
# show util message right away
|
| 35 |
+
log_item = self.agent.context.log.log(
|
| 36 |
+
type="util",
|
| 37 |
+
heading="Searching memories...",
|
| 38 |
+
)
|
| 39 |
+
|
| 40 |
task = asyncio.create_task(
|
| 41 |
+
self.search_memories(loop_data=loop_data, log_item=log_item, **kwargs)
|
| 42 |
)
|
| 43 |
else:
|
| 44 |
task = None
|
| 45 |
|
| 46 |
# set to agent to be able to wait for it
|
| 47 |
self.agent.set_data(DATA_NAME_TASK, task)
|
| 48 |
+
self.agent.set_data(DATA_NAME_ITER, loop_data.iteration)
|
| 49 |
|
| 50 |
+
async def search_memories(self, log_item: log.LogItem, loop_data: LoopData, **kwargs):
|
| 51 |
|
| 52 |
# cleanup
|
| 53 |
extras = loop_data.extras_persistent
|
|
|
|
| 60 |
set = settings.get_settings()
|
| 61 |
# try:
|
| 62 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 63 |
# get system message and chat history for util llm
|
| 64 |
system = self.agent.read_prompt("memory.memories_query.sys.md")
|
| 65 |
|
|
|
|
| 104 |
else:
|
| 105 |
query = user_instruction + "\n\n" + history
|
| 106 |
|
| 107 |
+
# if there is no query (or just dash by the LLM), do not continue
|
| 108 |
+
if not query or len(query) <= 3:
|
| 109 |
+
log_item.update(
|
| 110 |
+
query="No relevant memory query generated, skipping search",
|
| 111 |
+
)
|
| 112 |
+
return
|
| 113 |
+
|
| 114 |
# get memory database
|
| 115 |
db = await Memory.get(self.agent)
|
| 116 |
|
python/extensions/message_loop_prompts_after/_91_recall_wait.py
CHANGED
|
@@ -1,19 +1,32 @@
|
|
| 1 |
from python.helpers.extension import Extension
|
| 2 |
from agent import LoopData
|
| 3 |
-
from python.extensions.message_loop_prompts_after._50_recall_memories import DATA_NAME_TASK as DATA_NAME_TASK_MEMORIES
|
| 4 |
# from python.extensions.message_loop_prompts_after._51_recall_solutions import DATA_NAME_TASK as DATA_NAME_TASK_SOLUTIONS
|
| 5 |
-
|
| 6 |
|
| 7 |
class RecallWait(Extension):
|
| 8 |
async def execute(self, loop_data: LoopData = LoopData(), **kwargs):
|
| 9 |
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 14 |
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
|
|
|
|
| 1 |
from python.helpers.extension import Extension
|
| 2 |
from agent import LoopData
|
| 3 |
+
from python.extensions.message_loop_prompts_after._50_recall_memories import DATA_NAME_TASK as DATA_NAME_TASK_MEMORIES, DATA_NAME_ITER as DATA_NAME_ITER_MEMORIES
|
| 4 |
# from python.extensions.message_loop_prompts_after._51_recall_solutions import DATA_NAME_TASK as DATA_NAME_TASK_SOLUTIONS
|
| 5 |
+
from python.helpers import settings
|
| 6 |
|
| 7 |
class RecallWait(Extension):
|
| 8 |
async def execute(self, loop_data: LoopData = LoopData(), **kwargs):
|
| 9 |
|
| 10 |
+
set = settings.get_settings()
|
| 11 |
+
|
| 12 |
+
task = self.agent.get_data(DATA_NAME_TASK_MEMORIES)
|
| 13 |
+
iter = self.agent.get_data(DATA_NAME_ITER_MEMORIES) or 0
|
| 14 |
+
|
| 15 |
+
if task and not task.done():
|
| 16 |
+
|
| 17 |
+
# if memory recall is set to delayed mode, do not await on the iteration it was called
|
| 18 |
+
if set["memory_recall_delayed"]:
|
| 19 |
+
if iter == loop_data.iteration:
|
| 20 |
+
# insert info about delayed memory to extras
|
| 21 |
+
delay_text = self.agent.read_prompt("memory.recall_delay_msg.md")
|
| 22 |
+
loop_data.extras_temporary["memory_recall_delayed"] = delay_text
|
| 23 |
+
return
|
| 24 |
+
|
| 25 |
+
# otherwise await the task
|
| 26 |
+
await task
|
| 27 |
|
| 28 |
+
# task = self.agent.get_data(DATA_NAME_TASK_SOLUTIONS)
|
| 29 |
+
# if task and not task.done():
|
| 30 |
+
# # self.agent.context.log.set_progress("Recalling solutions...")
|
| 31 |
+
# await task
|
| 32 |
|
python/extensions/monologue_start/_10_memory_init.py
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from python.helpers.extension import Extension
|
| 2 |
+
from agent import LoopData
|
| 3 |
+
from python.helpers import memory
|
| 4 |
+
import asyncio
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
class MemoryInit(Extension):
|
| 8 |
+
|
| 9 |
+
async def execute(self, loop_data: LoopData = LoopData(), **kwargs):
|
| 10 |
+
db = await memory.Memory.get(self.agent)
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
|
python/helpers/settings.py
CHANGED
|
@@ -58,6 +58,7 @@ class Settings(TypedDict):
|
|
| 58 |
agent_knowledge_subdir: str
|
| 59 |
|
| 60 |
memory_recall_enabled: bool
|
|
|
|
| 61 |
memory_recall_interval: int
|
| 62 |
memory_recall_history_len: int
|
| 63 |
memory_recall_memories_max_search: int
|
|
@@ -643,6 +644,16 @@ def convert_out(settings: Settings) -> SettingsOutput:
|
|
| 643 |
}
|
| 644 |
)
|
| 645 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 646 |
memory_fields.append(
|
| 647 |
{
|
| 648 |
"id": "memory_recall_query_prep",
|
|
@@ -1319,7 +1330,7 @@ def get_default_settings() -> Settings:
|
|
| 1319 |
chat_model_rl_input=0,
|
| 1320 |
chat_model_rl_output=0,
|
| 1321 |
util_model_provider="openrouter",
|
| 1322 |
-
util_model_name="
|
| 1323 |
util_model_api_base="",
|
| 1324 |
util_model_ctx_length=100000,
|
| 1325 |
util_model_ctx_input=0.7,
|
|
@@ -1342,6 +1353,7 @@ def get_default_settings() -> Settings:
|
|
| 1342 |
browser_model_rl_output=0,
|
| 1343 |
browser_model_kwargs={"temperature": "0"},
|
| 1344 |
memory_recall_enabled=True,
|
|
|
|
| 1345 |
memory_recall_interval=3,
|
| 1346 |
memory_recall_history_len=10000,
|
| 1347 |
memory_recall_memories_max_search=12,
|
|
|
|
| 58 |
agent_knowledge_subdir: str
|
| 59 |
|
| 60 |
memory_recall_enabled: bool
|
| 61 |
+
memory_recall_delayed: bool
|
| 62 |
memory_recall_interval: int
|
| 63 |
memory_recall_history_len: int
|
| 64 |
memory_recall_memories_max_search: int
|
|
|
|
| 644 |
}
|
| 645 |
)
|
| 646 |
|
| 647 |
+
memory_fields.append(
|
| 648 |
+
{
|
| 649 |
+
"id": "memory_recall_delayed",
|
| 650 |
+
"title": "Memory auto-recall delayed",
|
| 651 |
+
"description": "The agent will not wait for auto memory recall. Memories will be delivered one message later. This speeds up agent's response time but may result in less relevant first step.",
|
| 652 |
+
"type": "switch",
|
| 653 |
+
"value": settings["memory_recall_delayed"],
|
| 654 |
+
}
|
| 655 |
+
)
|
| 656 |
+
|
| 657 |
memory_fields.append(
|
| 658 |
{
|
| 659 |
"id": "memory_recall_query_prep",
|
|
|
|
| 1330 |
chat_model_rl_input=0,
|
| 1331 |
chat_model_rl_output=0,
|
| 1332 |
util_model_provider="openrouter",
|
| 1333 |
+
util_model_name="google/gemini-2.5-flash-lite",
|
| 1334 |
util_model_api_base="",
|
| 1335 |
util_model_ctx_length=100000,
|
| 1336 |
util_model_ctx_input=0.7,
|
|
|
|
| 1353 |
browser_model_rl_output=0,
|
| 1354 |
browser_model_kwargs={"temperature": "0"},
|
| 1355 |
memory_recall_enabled=True,
|
| 1356 |
+
memory_recall_delayed=False,
|
| 1357 |
memory_recall_interval=3,
|
| 1358 |
memory_recall_history_len=10000,
|
| 1359 |
memory_recall_memories_max_search=12,
|