Spaces:
Paused
Paused
frdel
commited on
Commit
·
d912d1e
1
Parent(s):
d6e60a2
dev merge
Browse files- python/api/import_knowledge.py +16 -3
- python/api/nudge.py +0 -2
- python/api/poll.py +1 -0
- python/extensions/message_loop_prompts/_50_recall_memories.py +18 -9
- python/extensions/message_loop_prompts/_51_recall_solutions.py +10 -4
- python/extensions/message_loop_prompts/_90_organize_history_wait.py +2 -7
- python/extensions/message_loop_prompts/_91_recall_wait.py +19 -0
- python/extensions/monologue_end/_90_waiting_for_input_msg.py +1 -3
- python/helpers/log.py +162 -155
- python/helpers/memory.py +18 -1
- python/helpers/persist_chat.py +1 -2
- python/helpers/settings.py +1 -1
- webui/index.js +26 -5
python/api/import_knowledge.py
CHANGED
|
@@ -2,7 +2,7 @@ from python.helpers.api import ApiHandler
|
|
| 2 |
from flask import Request, Response
|
| 3 |
|
| 4 |
from python.helpers.file_browser import FileBrowser
|
| 5 |
-
from python.helpers import files
|
| 6 |
import os
|
| 7 |
from werkzeug.utils import secure_filename
|
| 8 |
|
|
@@ -12,8 +12,14 @@ class ImportKnowledge(ApiHandler):
|
|
| 12 |
if "files[]" not in request.files:
|
| 13 |
raise Exception("No files part")
|
| 14 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
file_list = request.files.getlist("files[]")
|
| 16 |
-
KNOWLEDGE_FOLDER = files.get_abs_path("
|
| 17 |
|
| 18 |
saved_filenames = []
|
| 19 |
|
|
@@ -23,4 +29,11 @@ class ImportKnowledge(ApiHandler):
|
|
| 23 |
file.save(os.path.join(KNOWLEDGE_FOLDER, filename))
|
| 24 |
saved_filenames.append(filename)
|
| 25 |
|
| 26 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2 |
from flask import Request, Response
|
| 3 |
|
| 4 |
from python.helpers.file_browser import FileBrowser
|
| 5 |
+
from python.helpers import files, memory
|
| 6 |
import os
|
| 7 |
from werkzeug.utils import secure_filename
|
| 8 |
|
|
|
|
| 12 |
if "files[]" not in request.files:
|
| 13 |
raise Exception("No files part")
|
| 14 |
|
| 15 |
+
ctxid = request.form.get("ctxid", "")
|
| 16 |
+
if not ctxid:
|
| 17 |
+
raise Exception("No context id provided")
|
| 18 |
+
|
| 19 |
+
context = self.get_context(ctxid)
|
| 20 |
+
|
| 21 |
file_list = request.files.getlist("files[]")
|
| 22 |
+
KNOWLEDGE_FOLDER = files.get_abs_path(memory.get_custom_knowledge_subdir_abs(context.agent0),"main")
|
| 23 |
|
| 24 |
saved_filenames = []
|
| 25 |
|
|
|
|
| 29 |
file.save(os.path.join(KNOWLEDGE_FOLDER, filename))
|
| 30 |
saved_filenames.append(filename)
|
| 31 |
|
| 32 |
+
#reload memory to re-import knowledge
|
| 33 |
+
await memory.Memory.reload(context.agent0)
|
| 34 |
+
context.log.set_initial_progress()
|
| 35 |
+
|
| 36 |
+
return {
|
| 37 |
+
"message": "Knowledge Imported",
|
| 38 |
+
"filenames": saved_filenames[:5]
|
| 39 |
+
}
|
python/api/nudge.py
CHANGED
|
@@ -1,8 +1,6 @@
|
|
| 1 |
from python.helpers.api import ApiHandler
|
| 2 |
from flask import Request, Response
|
| 3 |
|
| 4 |
-
from python.helpers import persist_chat
|
| 5 |
-
|
| 6 |
class Nudge(ApiHandler):
|
| 7 |
async def process(self, input: dict, request: Request) -> dict | Response:
|
| 8 |
ctxid = input.get("ctxid", "")
|
|
|
|
| 1 |
from python.helpers.api import ApiHandler
|
| 2 |
from flask import Request, Response
|
| 3 |
|
|
|
|
|
|
|
| 4 |
class Nudge(ApiHandler):
|
| 5 |
async def process(self, input: dict, request: Request) -> dict | Response:
|
| 6 |
ctxid = input.get("ctxid", "")
|
python/api/poll.py
CHANGED
|
@@ -35,5 +35,6 @@ class Poll(ApiHandler):
|
|
| 35 |
"log_guid": context.log.guid,
|
| 36 |
"log_version": len(context.log.updates),
|
| 37 |
"log_progress": context.log.progress,
|
|
|
|
| 38 |
"paused": context.paused,
|
| 39 |
}
|
|
|
|
| 35 |
"log_guid": context.log.guid,
|
| 36 |
"log_version": len(context.log.updates),
|
| 37 |
"log_progress": context.log.progress,
|
| 38 |
+
"log_progress_active": context.log.progress_active,
|
| 39 |
"paused": context.paused,
|
| 40 |
}
|
python/extensions/message_loop_prompts/_50_recall_memories.py
CHANGED
|
@@ -1,29 +1,36 @@
|
|
|
|
|
| 1 |
from python.helpers.extension import Extension
|
| 2 |
from python.helpers.memory import Memory
|
| 3 |
from agent import LoopData
|
| 4 |
|
|
|
|
| 5 |
|
| 6 |
class RecallMemories(Extension):
|
| 7 |
|
| 8 |
INTERVAL = 3
|
| 9 |
-
HISTORY = 5
|
| 10 |
RESULTS = 3
|
| 11 |
THRESHOLD = 0.6
|
| 12 |
|
| 13 |
async def execute(self, loop_data: LoopData = LoopData(), **kwargs):
|
| 14 |
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 19 |
|
| 20 |
async def search_memories(self, loop_data: LoopData, **kwargs):
|
| 21 |
|
| 22 |
-
#cleanup
|
| 23 |
extras = loop_data.extras_temporary
|
| 24 |
if "memories" in extras:
|
| 25 |
del extras["memories"]
|
| 26 |
-
|
| 27 |
# try:
|
| 28 |
# show temp info message
|
| 29 |
self.agent.context.log.log(
|
|
@@ -51,7 +58,9 @@ class RecallMemories(Extension):
|
|
| 51 |
|
| 52 |
# call util llm to summarize conversation
|
| 53 |
query = await self.agent.call_utility_llm(
|
| 54 |
-
system=system,
|
|
|
|
|
|
|
| 55 |
)
|
| 56 |
|
| 57 |
# get solutions database
|
|
@@ -91,7 +100,7 @@ class RecallMemories(Extension):
|
|
| 91 |
|
| 92 |
# append to prompt
|
| 93 |
extras["memories"] = memories_prompt
|
| 94 |
-
|
| 95 |
# except Exception as e:
|
| 96 |
# err = errors.format_error(e)
|
| 97 |
# self.agent.context.log.log(
|
|
|
|
| 1 |
+
import asyncio
|
| 2 |
from python.helpers.extension import Extension
|
| 3 |
from python.helpers.memory import Memory
|
| 4 |
from agent import LoopData
|
| 5 |
|
| 6 |
+
DATA_NAME_TASK = "_recall_memories_task"
|
| 7 |
|
| 8 |
class RecallMemories(Extension):
|
| 9 |
|
| 10 |
INTERVAL = 3
|
| 11 |
+
HISTORY = 5 # TODO cleanup
|
| 12 |
RESULTS = 3
|
| 13 |
THRESHOLD = 0.6
|
| 14 |
|
| 15 |
async def execute(self, loop_data: LoopData = LoopData(), **kwargs):
|
| 16 |
|
| 17 |
+
# every 3 iterations (or the first one) recall memories
|
| 18 |
+
if loop_data.iteration % RecallMemories.INTERVAL == 0:
|
| 19 |
+
task = asyncio.create_task(self.search_memories(loop_data=loop_data, **kwargs))
|
| 20 |
+
else:
|
| 21 |
+
task = None
|
| 22 |
+
|
| 23 |
+
# set to agent to be able to wait for it
|
| 24 |
+
self.agent.set_data(DATA_NAME_TASK, task)
|
| 25 |
+
|
| 26 |
|
| 27 |
async def search_memories(self, loop_data: LoopData, **kwargs):
|
| 28 |
|
| 29 |
+
# cleanup
|
| 30 |
extras = loop_data.extras_temporary
|
| 31 |
if "memories" in extras:
|
| 32 |
del extras["memories"]
|
| 33 |
+
|
| 34 |
# try:
|
| 35 |
# show temp info message
|
| 36 |
self.agent.context.log.log(
|
|
|
|
| 58 |
|
| 59 |
# call util llm to summarize conversation
|
| 60 |
query = await self.agent.call_utility_llm(
|
| 61 |
+
system=system,
|
| 62 |
+
msg=loop_data.user_message.output_text() if loop_data.user_message else "",
|
| 63 |
+
callback=log_callback,
|
| 64 |
)
|
| 65 |
|
| 66 |
# get solutions database
|
|
|
|
| 100 |
|
| 101 |
# append to prompt
|
| 102 |
extras["memories"] = memories_prompt
|
| 103 |
+
|
| 104 |
# except Exception as e:
|
| 105 |
# err = errors.format_error(e)
|
| 106 |
# self.agent.context.log.log(
|
python/extensions/message_loop_prompts/_51_recall_solutions.py
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
|
|
| 1 |
from python.helpers.extension import Extension
|
| 2 |
from python.helpers.memory import Memory
|
| 3 |
from agent import LoopData
|
| 4 |
|
|
|
|
| 5 |
|
| 6 |
class RecallSolutions(Extension):
|
| 7 |
|
|
@@ -13,10 +15,14 @@ class RecallSolutions(Extension):
|
|
| 13 |
|
| 14 |
async def execute(self, loop_data: LoopData = LoopData(), **kwargs):
|
| 15 |
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 20 |
|
| 21 |
async def search_solutions(self, loop_data: LoopData, **kwargs):
|
| 22 |
|
|
|
|
| 1 |
+
import asyncio
|
| 2 |
from python.helpers.extension import Extension
|
| 3 |
from python.helpers.memory import Memory
|
| 4 |
from agent import LoopData
|
| 5 |
|
| 6 |
+
DATA_NAME_TASK = "_recall_solutions_task"
|
| 7 |
|
| 8 |
class RecallSolutions(Extension):
|
| 9 |
|
|
|
|
| 15 |
|
| 16 |
async def execute(self, loop_data: LoopData = LoopData(), **kwargs):
|
| 17 |
|
| 18 |
+
# every 3 iterations (or the first one) recall memories
|
| 19 |
+
if loop_data.iteration % RecallSolutions.INTERVAL == 0:
|
| 20 |
+
task = asyncio.create_task(self.search_solutions(loop_data=loop_data, **kwargs))
|
| 21 |
+
else:
|
| 22 |
+
task = None
|
| 23 |
+
|
| 24 |
+
# set to agent to be able to wait for it
|
| 25 |
+
self.agent.set_data(DATA_NAME_TASK, task)
|
| 26 |
|
| 27 |
async def search_solutions(self, loop_data: LoopData, **kwargs):
|
| 28 |
|
python/extensions/message_loop_prompts/_90_organize_history_wait.py
CHANGED
|
@@ -15,7 +15,7 @@ class OrganizeHistoryWait(Extension):
|
|
| 15 |
# Check if the task is already done
|
| 16 |
if task:
|
| 17 |
if not task.done():
|
| 18 |
-
self.log()
|
| 19 |
|
| 20 |
# Wait for the task to complete
|
| 21 |
await task
|
|
@@ -24,11 +24,6 @@ class OrganizeHistoryWait(Extension):
|
|
| 24 |
self.agent.set_data(DATA_NAME_TASK, None)
|
| 25 |
else:
|
| 26 |
# no task running, start and wait
|
| 27 |
-
self.log()
|
| 28 |
await self.agent.history.compress()
|
| 29 |
|
| 30 |
-
def log(self):
|
| 31 |
-
if not hasattr(self, 'log_item') or not self.log_item:
|
| 32 |
-
self.log_item = self.agent.context.log.log(
|
| 33 |
-
type="util", heading="Waiting for history to be compressed..."
|
| 34 |
-
)
|
|
|
|
| 15 |
# Check if the task is already done
|
| 16 |
if task:
|
| 17 |
if not task.done():
|
| 18 |
+
self.agent.context.log.set_progress("Compressing history...")
|
| 19 |
|
| 20 |
# Wait for the task to complete
|
| 21 |
await task
|
|
|
|
| 24 |
self.agent.set_data(DATA_NAME_TASK, None)
|
| 25 |
else:
|
| 26 |
# no task running, start and wait
|
| 27 |
+
self.agent.context.log.set_progress("Compressing history...")
|
| 28 |
await self.agent.history.compress()
|
| 29 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
python/extensions/message_loop_prompts/_91_recall_wait.py
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from python.helpers.extension import Extension
|
| 2 |
+
from agent import LoopData
|
| 3 |
+
from python.extensions.message_loop_prompts._50_recall_memories import DATA_NAME_TASK as DATA_NAME_TASK_MEMORIES
|
| 4 |
+
from python.extensions.message_loop_prompts._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 |
+
task = self.agent.get_data(DATA_NAME_TASK_MEMORIES)
|
| 11 |
+
if task and not task.done():
|
| 12 |
+
self.agent.context.log.set_progress("Recalling memories...")
|
| 13 |
+
await task
|
| 14 |
+
|
| 15 |
+
task = self.agent.get_data(DATA_NAME_TASK_SOLUTIONS)
|
| 16 |
+
if task and not task.done():
|
| 17 |
+
self.agent.context.log.set_progress("Recalling solutions...")
|
| 18 |
+
await task
|
| 19 |
+
|
python/extensions/monologue_end/_90_waiting_for_input_msg.py
CHANGED
|
@@ -6,7 +6,5 @@ class WaitingForInputMsg(Extension):
|
|
| 6 |
async def execute(self, loop_data: LoopData = LoopData(), **kwargs):
|
| 7 |
# show temp info message
|
| 8 |
if self.agent.number == 0:
|
| 9 |
-
self.agent.context.log.
|
| 10 |
-
type="util", heading="Waiting for input", temp=True
|
| 11 |
-
)
|
| 12 |
|
|
|
|
| 6 |
async def execute(self, loop_data: LoopData = LoopData(), **kwargs):
|
| 7 |
# show temp info message
|
| 8 |
if self.agent.number == 0:
|
| 9 |
+
self.agent.context.log.set_initial_progress()
|
|
|
|
|
|
|
| 10 |
|
python/helpers/log.py
CHANGED
|
@@ -5,165 +5,172 @@ import uuid
|
|
| 5 |
from collections import OrderedDict # Import OrderedDict
|
| 6 |
|
| 7 |
Type = Literal[
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
|
|
|
| 19 |
]
|
| 20 |
|
| 21 |
@dataclass
|
| 22 |
class LogItem:
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
|
| 76 |
|
| 77 |
class Log:
|
| 78 |
|
| 79 |
-
|
| 80 |
-
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
|
| 95 |
-
|
| 96 |
-
|
| 97 |
-
|
| 98 |
-
|
| 99 |
-
|
| 100 |
-
|
| 101 |
-
|
| 102 |
-
|
| 103 |
-
|
| 104 |
-
|
| 105 |
-
|
| 106 |
-
|
| 107 |
-
|
| 108 |
-
|
| 109 |
-
|
| 110 |
-
|
| 111 |
-
|
| 112 |
-
|
| 113 |
-
|
| 114 |
-
|
| 115 |
-
|
| 116 |
-
|
| 117 |
-
|
| 118 |
-
|
| 119 |
-
|
| 120 |
-
|
| 121 |
-
|
| 122 |
-
|
| 123 |
-
|
| 124 |
-
|
| 125 |
-
|
| 126 |
-
|
| 127 |
-
|
| 128 |
-
|
| 129 |
-
|
| 130 |
-
|
| 131 |
-
|
| 132 |
-
|
| 133 |
-
|
| 134 |
-
|
| 135 |
-
|
| 136 |
-
|
| 137 |
-
|
| 138 |
-
|
| 139 |
-
|
| 140 |
-
|
| 141 |
-
|
| 142 |
-
|
| 143 |
-
|
| 144 |
-
|
| 145 |
-
|
| 146 |
-
|
| 147 |
-
|
| 148 |
-
|
| 149 |
-
|
| 150 |
-
|
| 151 |
-
|
| 152 |
-
|
| 153 |
-
|
| 154 |
-
|
| 155 |
-
|
| 156 |
-
|
| 157 |
-
|
| 158 |
-
|
| 159 |
-
|
| 160 |
-
|
| 161 |
-
|
| 162 |
-
|
| 163 |
-
|
| 164 |
-
|
| 165 |
-
|
| 166 |
-
|
| 167 |
-
|
| 168 |
-
|
| 169 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5 |
from collections import OrderedDict # Import OrderedDict
|
| 6 |
|
| 7 |
Type = Literal[
|
| 8 |
+
"agent",
|
| 9 |
+
"code_exe",
|
| 10 |
+
"error",
|
| 11 |
+
"hint",
|
| 12 |
+
"info",
|
| 13 |
+
"progress",
|
| 14 |
+
"response",
|
| 15 |
+
"tool",
|
| 16 |
+
"input",
|
| 17 |
+
"user",
|
| 18 |
+
"util",
|
| 19 |
+
"warning",
|
| 20 |
]
|
| 21 |
|
| 22 |
@dataclass
|
| 23 |
class LogItem:
|
| 24 |
+
log: "Log"
|
| 25 |
+
no: int
|
| 26 |
+
type: str
|
| 27 |
+
heading: str
|
| 28 |
+
content: str
|
| 29 |
+
temp: bool
|
| 30 |
+
kvps: Optional[OrderedDict] = None # Use OrderedDict for kvps
|
| 31 |
+
id: Optional[str] = None # Add id field
|
| 32 |
+
guid: str = ""
|
| 33 |
+
|
| 34 |
+
def __post_init__(self):
|
| 35 |
+
self.guid = self.log.guid
|
| 36 |
+
|
| 37 |
+
def update(
|
| 38 |
+
self,
|
| 39 |
+
type: Type | None = None,
|
| 40 |
+
heading: str | None = None,
|
| 41 |
+
content: str | None = None,
|
| 42 |
+
kvps: dict | None = None,
|
| 43 |
+
temp: bool | None = None,
|
| 44 |
+
**kwargs,
|
| 45 |
+
):
|
| 46 |
+
if self.guid == self.log.guid:
|
| 47 |
+
self.log.update_item(
|
| 48 |
+
self.no,
|
| 49 |
+
type=type,
|
| 50 |
+
heading=heading,
|
| 51 |
+
content=content,
|
| 52 |
+
kvps=kvps,
|
| 53 |
+
temp=temp,
|
| 54 |
+
**kwargs,
|
| 55 |
+
)
|
| 56 |
+
|
| 57 |
+
def stream(self, heading: str | None = None, content: str | None = None, **kwargs):
|
| 58 |
+
if heading is not None:
|
| 59 |
+
self.update(heading=self.heading + heading)
|
| 60 |
+
if content is not None:
|
| 61 |
+
self.update(content=self.content + content)
|
| 62 |
+
|
| 63 |
+
for k, v in kwargs.items():
|
| 64 |
+
prev = self.kvps.get(k, "") if self.kvps else ""
|
| 65 |
+
self.update(**{k: prev + v})
|
| 66 |
+
|
| 67 |
+
def output(self):
|
| 68 |
+
return {
|
| 69 |
+
"no": self.no,
|
| 70 |
+
"id": self.id, # Include id in output
|
| 71 |
+
"type": self.type,
|
| 72 |
+
"heading": self.heading,
|
| 73 |
+
"content": self.content,
|
| 74 |
+
"temp": self.temp,
|
| 75 |
+
"kvps": self.kvps,
|
| 76 |
+
}
|
| 77 |
|
| 78 |
class Log:
|
| 79 |
|
| 80 |
+
def __init__(self):
|
| 81 |
+
self.guid: str = str(uuid.uuid4())
|
| 82 |
+
self.updates: list[int] = []
|
| 83 |
+
self.logs: list[LogItem] = []
|
| 84 |
+
self.set_initial_progress()
|
| 85 |
+
|
| 86 |
+
def log(
|
| 87 |
+
self,
|
| 88 |
+
type: Type,
|
| 89 |
+
heading: str | None = None,
|
| 90 |
+
content: str | None = None,
|
| 91 |
+
kvps: dict | None = None,
|
| 92 |
+
temp: bool | None = None,
|
| 93 |
+
id: Optional[str] = None, # Add id parameter
|
| 94 |
+
) -> LogItem:
|
| 95 |
+
# Use OrderedDict if kvps is provided
|
| 96 |
+
if kvps is not None:
|
| 97 |
+
kvps = OrderedDict(kvps)
|
| 98 |
+
item = LogItem(
|
| 99 |
+
log=self,
|
| 100 |
+
no=len(self.logs),
|
| 101 |
+
type=type,
|
| 102 |
+
heading=heading or "",
|
| 103 |
+
content=content or "",
|
| 104 |
+
kvps=kvps,
|
| 105 |
+
temp=temp or False,
|
| 106 |
+
id=id, # Pass id to LogItem
|
| 107 |
+
)
|
| 108 |
+
self.logs.append(item)
|
| 109 |
+
self.updates += [item.no]
|
| 110 |
+
if heading and item.no >= self.progress_no:
|
| 111 |
+
self.set_progress(heading, item.no)
|
| 112 |
+
return item
|
| 113 |
+
|
| 114 |
+
def update_item(
|
| 115 |
+
self,
|
| 116 |
+
no: int,
|
| 117 |
+
type: str | None = None,
|
| 118 |
+
heading: str | None = None,
|
| 119 |
+
content: str | None = None,
|
| 120 |
+
kvps: dict | None = None,
|
| 121 |
+
temp: bool | None = None,
|
| 122 |
+
**kwargs,
|
| 123 |
+
):
|
| 124 |
+
item = self.logs[no]
|
| 125 |
+
if type is not None:
|
| 126 |
+
item.type = type
|
| 127 |
+
if heading is not None:
|
| 128 |
+
item.heading = heading
|
| 129 |
+
if no >= self.progress_no:
|
| 130 |
+
self.set_progress(heading, no)
|
| 131 |
+
if content is not None:
|
| 132 |
+
item.content = content
|
| 133 |
+
if kvps is not None:
|
| 134 |
+
item.kvps = OrderedDict(kvps) # Use OrderedDict to keep the order
|
| 135 |
+
|
| 136 |
+
if temp is not None:
|
| 137 |
+
item.temp = temp
|
| 138 |
+
|
| 139 |
+
if kwargs:
|
| 140 |
+
if item.kvps is None:
|
| 141 |
+
item.kvps = OrderedDict() # Ensure kvps is an OrderedDict
|
| 142 |
+
for k, v in kwargs.items():
|
| 143 |
+
item.kvps[k] = v
|
| 144 |
+
|
| 145 |
+
self.updates += [item.no]
|
| 146 |
+
|
| 147 |
+
def set_progress(self, progress: str, no: int = 0, active: bool = True):
|
| 148 |
+
self.progress = progress
|
| 149 |
+
if not no:
|
| 150 |
+
no = len(self.logs)
|
| 151 |
+
self.progress_no = no
|
| 152 |
+
self.progress_active = active
|
| 153 |
+
|
| 154 |
+
def set_initial_progress(self):
|
| 155 |
+
self.set_progress("Waiting for input", 0, False)
|
| 156 |
+
|
| 157 |
+
def output(self, start=None, end=None):
|
| 158 |
+
if start is None:
|
| 159 |
+
start = 0
|
| 160 |
+
if end is None:
|
| 161 |
+
end = len(self.updates)
|
| 162 |
+
|
| 163 |
+
out = []
|
| 164 |
+
seen = set()
|
| 165 |
+
for update in self.updates[start:end]:
|
| 166 |
+
if update not in seen:
|
| 167 |
+
out.append(self.logs[update].output())
|
| 168 |
+
seen.add(update)
|
| 169 |
+
|
| 170 |
+
return out
|
| 171 |
+
|
| 172 |
+
def reset(self):
|
| 173 |
+
self.guid = str(uuid.uuid4())
|
| 174 |
+
self.updates = []
|
| 175 |
+
self.logs = []
|
| 176 |
+
self.set_initial_progress()
|
python/helpers/memory.py
CHANGED
|
@@ -72,6 +72,13 @@ class Memory:
|
|
| 72 |
memory_subdir=memory_subdir,
|
| 73 |
)
|
| 74 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 75 |
@staticmethod
|
| 76 |
def initialize(
|
| 77 |
log_item: LogItem | None,
|
|
@@ -151,6 +158,9 @@ class Memory:
|
|
| 151 |
async def preload_knowledge(
|
| 152 |
self, log_item: LogItem | None, kn_dirs: list[str], memory_subdir: str
|
| 153 |
):
|
|
|
|
|
|
|
|
|
|
| 154 |
# db abs path
|
| 155 |
db_dir = Memory._abs_db_dir(memory_subdir)
|
| 156 |
|
|
@@ -351,5 +361,12 @@ class Memory:
|
|
| 351 |
def get_timestamp():
|
| 352 |
return datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
| 353 |
|
|
|
|
| 354 |
def get_memory_subdir_abs(agent: Agent) -> str:
|
| 355 |
-
return files.get_abs_path("memory", agent.config.memory_subdir or "default")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 72 |
memory_subdir=memory_subdir,
|
| 73 |
)
|
| 74 |
|
| 75 |
+
@staticmethod
|
| 76 |
+
async def reload(agent: Agent):
|
| 77 |
+
memory_subdir = agent.config.memory_subdir or "default"
|
| 78 |
+
if Memory.index.get(memory_subdir):
|
| 79 |
+
del Memory.index[memory_subdir]
|
| 80 |
+
return await Memory.get(agent)
|
| 81 |
+
|
| 82 |
@staticmethod
|
| 83 |
def initialize(
|
| 84 |
log_item: LogItem | None,
|
|
|
|
| 158 |
async def preload_knowledge(
|
| 159 |
self, log_item: LogItem | None, kn_dirs: list[str], memory_subdir: str
|
| 160 |
):
|
| 161 |
+
if log_item:
|
| 162 |
+
log_item.update(heading="Preloading knowledge...")
|
| 163 |
+
|
| 164 |
# db abs path
|
| 165 |
db_dir = Memory._abs_db_dir(memory_subdir)
|
| 166 |
|
|
|
|
| 361 |
def get_timestamp():
|
| 362 |
return datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
| 363 |
|
| 364 |
+
|
| 365 |
def get_memory_subdir_abs(agent: Agent) -> str:
|
| 366 |
+
return files.get_abs_path("memory", agent.config.memory_subdir or "default")
|
| 367 |
+
|
| 368 |
+
def get_custom_knowledge_subdir_abs(agent: Agent) -> str:
|
| 369 |
+
for dir in agent.config.knowledge_subdirs:
|
| 370 |
+
if dir != "default":
|
| 371 |
+
return files.get_abs_path("knowledge", dir)
|
| 372 |
+
raise Exception("No custom knowledge subdir set")
|
python/helpers/persist_chat.py
CHANGED
|
@@ -166,8 +166,7 @@ def _deserialize_agents(
|
|
| 166 |
def _deserialize_log(data: dict[str, Any]) -> "Log":
|
| 167 |
log = Log()
|
| 168 |
log.guid = data.get("guid", str(uuid.uuid4()))
|
| 169 |
-
log.
|
| 170 |
-
log.progress_no = data.get("progress_no", 0)
|
| 171 |
|
| 172 |
# Deserialize the list of LogItem objects
|
| 173 |
i = 0
|
|
|
|
| 166 |
def _deserialize_log(data: dict[str, Any]) -> "Log":
|
| 167 |
log = Log()
|
| 168 |
log.guid = data.get("guid", str(uuid.uuid4()))
|
| 169 |
+
log.set_initial_progress()
|
|
|
|
| 170 |
|
| 171 |
# Deserialize the list of LogItem objects
|
| 172 |
i = 0
|
python/helpers/settings.py
CHANGED
|
@@ -703,7 +703,7 @@ def get_default_settings() -> Settings:
|
|
| 703 |
chat_model_temperature=0,
|
| 704 |
chat_model_kwargs={},
|
| 705 |
chat_model_ctx_length=8192,
|
| 706 |
-
chat_model_ctx_history=0.
|
| 707 |
util_model_provider=ModelProvider.OPENAI.name,
|
| 708 |
util_model_name="gpt-4o-mini",
|
| 709 |
util_model_temperature=0,
|
|
|
|
| 703 |
chat_model_temperature=0,
|
| 704 |
chat_model_kwargs={},
|
| 705 |
chat_model_ctx_length=8192,
|
| 706 |
+
chat_model_ctx_history=0.7,
|
| 707 |
util_model_provider=ModelProvider.OPENAI.name,
|
| 708 |
util_model_name="gpt-4o-mini",
|
| 709 |
util_model_temperature=0,
|
webui/index.js
CHANGED
|
@@ -269,6 +269,8 @@ window.loadKnowledge = async function () {
|
|
| 269 |
formData.append('files[]', file);
|
| 270 |
}
|
| 271 |
|
|
|
|
|
|
|
| 272 |
const response = await fetch('/import_knowledge', {
|
| 273 |
method: 'POST',
|
| 274 |
body: formData,
|
|
@@ -357,7 +359,7 @@ async function poll() {
|
|
| 357 |
afterMessagesUpdate(response.logs)
|
| 358 |
}
|
| 359 |
|
| 360 |
-
updateProgress(response.log_progress)
|
| 361 |
|
| 362 |
//set ui model vars from backend
|
| 363 |
const inputAD = Alpine.$data(inputSection);
|
|
@@ -400,11 +402,30 @@ function speakMessages(logs) {
|
|
| 400 |
}
|
| 401 |
}
|
| 402 |
|
| 403 |
-
function
|
| 404 |
-
|
| 405 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 406 |
|
| 407 |
-
if (
|
| 408 |
removeClassFromElement(progressBar, "shiny-text")
|
| 409 |
} else {
|
| 410 |
addClassToElement(progressBar, "shiny-text")
|
|
|
|
| 269 |
formData.append('files[]', file);
|
| 270 |
}
|
| 271 |
|
| 272 |
+
formData.append('ctxid', getContext());
|
| 273 |
+
|
| 274 |
const response = await fetch('/import_knowledge', {
|
| 275 |
method: 'POST',
|
| 276 |
body: formData,
|
|
|
|
| 359 |
afterMessagesUpdate(response.logs)
|
| 360 |
}
|
| 361 |
|
| 362 |
+
updateProgress(response.log_progress, response.log_progress_active)
|
| 363 |
|
| 364 |
//set ui model vars from backend
|
| 365 |
const inputAD = Alpine.$data(inputSection);
|
|
|
|
| 402 |
}
|
| 403 |
}
|
| 404 |
|
| 405 |
+
function afterMessagesUpdate(logs) {
|
| 406 |
+
if (localStorage.getItem('speech') == 'true') {
|
| 407 |
+
speakMessages(logs)
|
| 408 |
+
}
|
| 409 |
+
}
|
| 410 |
+
|
| 411 |
+
function speakMessages(logs) {
|
| 412 |
+
// log.no, log.type, log.heading, log.content
|
| 413 |
+
for (let i = logs.length - 1; i >= 0; i--) {
|
| 414 |
+
const log = logs[i]
|
| 415 |
+
if (log.type == "response") {
|
| 416 |
+
if (log.no > lastSpokenNo) {
|
| 417 |
+
lastSpokenNo = log.no
|
| 418 |
+
speech.speak(log.content)
|
| 419 |
+
return
|
| 420 |
+
}
|
| 421 |
+
}
|
| 422 |
+
}
|
| 423 |
+
}
|
| 424 |
+
|
| 425 |
+
function updateProgress(progress, active) {
|
| 426 |
+
if (!progress) progress = ""
|
| 427 |
|
| 428 |
+
if (!active) {
|
| 429 |
removeClassFromElement(progressBar, "shiny-text")
|
| 430 |
} else {
|
| 431 |
addClassToElement(progressBar, "shiny-text")
|