frdel commited on
Commit
a1fe360
·
1 Parent(s): 215a369

Memory recall speedup

Browse files
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/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 # TODO cleanup
10
  RESULTS = 3
11
  THRESHOLD = 0.6
12
 
13
  async def execute(self, loop_data: LoopData = LoopData(), **kwargs):
14
 
15
- if (
16
- loop_data.iteration % RecallMemories.INTERVAL == 0
17
- ): # every 3 iterations (or the first one) recall memories
18
- await self.search_memories(loop_data=loop_data, **kwargs)
 
 
 
 
 
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, msg=loop_data.user_message.output_text() if loop_data.user_message else "", callback=log_callback
 
 
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
- if (
17
- loop_data.iteration % RecallSolutions.INTERVAL == 0
18
- ): # every 3 iterations (or the first one) recall solution memories
19
- await self.search_solutions(loop_data=loop_data, **kwargs)
 
 
 
 
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/helpers/log.py CHANGED
@@ -5,165 +5,172 @@ import uuid
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
- "user",
17
- "util",
18
- "warning",
 
19
  ]
20
 
 
21
  @dataclass
22
  class LogItem:
23
- log: "Log"
24
- no: int
25
- type: str
26
- heading: str
27
- content: str
28
- temp: bool
29
- kvps: Optional[OrderedDict] = None # Use OrderedDict for kvps
30
- id: Optional[str] = None # Add id field
31
- guid: str = ""
32
-
33
- def __post_init__(self):
34
- self.guid = self.log.guid
35
-
36
- def update(
37
- self,
38
- type: Type | None = None,
39
- heading: str | None = None,
40
- content: str | None = None,
41
- kvps: dict | None = None,
42
- temp: bool | None = None,
43
- **kwargs,
44
- ):
45
- if self.guid == self.log.guid:
46
- self.log.update_item(
47
- self.no,
48
- type=type,
49
- heading=heading,
50
- content=content,
51
- kvps=kvps,
52
- temp=temp,
53
- **kwargs,
54
- )
55
-
56
- def stream(self, heading: str | None = None, content: str | None = None, **kwargs):
57
- if heading is not None:
58
- self.update(heading=self.heading + heading)
59
- if content is not None:
60
- self.update(content=self.content + content)
61
-
62
- for k, v in kwargs.items():
63
- prev = self.kvps.get(k, "") if self.kvps else ""
64
- self.update(**{k: prev + v})
65
-
66
- def output(self):
67
- return {
68
- "no": self.no,
69
- "id": self.id, # Include id in output
70
- "type": self.type,
71
- "heading": self.heading,
72
- "content": self.content,
73
- "temp": self.temp,
74
- "kvps": self.kvps,
75
- }
 
76
 
77
  class Log:
78
 
79
- def __init__(self):
80
- self.guid: str = str(uuid.uuid4())
81
- self.updates: list[int] = []
82
- self.logs: list[LogItem] = []
83
- self.progress = ""
84
- self.progress_no = 0
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.progress = heading
112
- self.progress_no = item.no
113
- return item
114
-
115
- def update_item(
116
- self,
117
- no: int,
118
- type: str | None = None,
119
- heading: str | None = None,
120
- content: str | None = None,
121
- kvps: dict | None = None,
122
- temp: bool | None = None,
123
- **kwargs,
124
- ):
125
- item = self.logs[no]
126
- if type is not None:
127
- item.type = type
128
- if heading is not None:
129
- item.heading = heading
130
- if no >= self.progress_no:
131
- self.progress = heading
132
- self.progress_no = no
133
- if content is not None:
134
- item.content = content
135
- if kvps is not None:
136
- item.kvps = OrderedDict(kvps) # Use OrderedDict to keep the order
137
-
138
- if temp is not None:
139
- item.temp = temp
140
-
141
- if kwargs:
142
- if item.kvps is None:
143
- item.kvps = OrderedDict() # Ensure kvps is an OrderedDict
144
- for k, v in kwargs.items():
145
- item.kvps[k] = v
146
-
147
- self.updates += [item.no]
148
-
149
- def output(self, start=None, end=None):
150
- if start is None:
151
- start = 0
152
- if end is None:
153
- end = len(self.updates)
154
-
155
- out = []
156
- seen = set()
157
- for update in self.updates[start:end]:
158
- if update not in seen:
159
- out.append(self.logs[update].output())
160
- seen.add(update)
161
-
162
- return out
163
-
164
- def reset(self):
165
- self.guid = str(uuid.uuid4())
166
- self.updates = []
167
- self.logs = []
168
- self.progress = ""
169
- self.progress_no = 0
 
 
 
 
 
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
+
23
  @dataclass
24
  class LogItem:
25
+ log: "Log"
26
+ no: int
27
+ type: str
28
+ heading: str
29
+ content: str
30
+ temp: bool
31
+ kvps: Optional[OrderedDict] = None # Use OrderedDict for kvps
32
+ id: Optional[str] = None # Add id field
33
+ guid: str = ""
34
+
35
+ def __post_init__(self):
36
+ self.guid = self.log.guid
37
+
38
+ def update(
39
+ self,
40
+ type: Type | None = None,
41
+ heading: str | None = None,
42
+ content: str | None = None,
43
+ kvps: dict | None = None,
44
+ temp: bool | None = None,
45
+ **kwargs,
46
+ ):
47
+ if self.guid == self.log.guid:
48
+ self.log.update_item(
49
+ self.no,
50
+ type=type,
51
+ heading=heading,
52
+ content=content,
53
+ kvps=kvps,
54
+ temp=temp,
55
+ **kwargs,
56
+ )
57
+
58
+ def stream(self, heading: str | None = None, content: str | None = None, **kwargs):
59
+ if heading is not None:
60
+ self.update(heading=self.heading + heading)
61
+ if content is not None:
62
+ self.update(content=self.content + content)
63
+
64
+ for k, v in kwargs.items():
65
+ prev = self.kvps.get(k, "") if self.kvps else ""
66
+ self.update(**{k: prev + v})
67
+
68
+ def output(self):
69
+ return {
70
+ "no": self.no,
71
+ "id": self.id, # Include id in output
72
+ "type": self.type,
73
+ "heading": self.heading,
74
+ "content": self.content,
75
+ "temp": self.temp,
76
+ "kvps": self.kvps,
77
+ }
78
+
79
 
80
  class Log:
81
 
82
+ def __init__(self):
83
+ self.guid: str = str(uuid.uuid4())
84
+ self.updates: list[int] = []
85
+ self.logs: list[LogItem] = []
86
+ self.progress = ""
87
+ self.progress_no = 0
88
+
89
+ def log(
90
+ self,
91
+ type: Type,
92
+ heading: str | None = None,
93
+ content: str | None = None,
94
+ kvps: dict | None = None,
95
+ temp: bool | None = None,
96
+ id: Optional[str] = None, # Add id parameter
97
+ ) -> LogItem:
98
+ # Use OrderedDict if kvps is provided
99
+ if kvps is not None:
100
+ kvps = OrderedDict(kvps)
101
+ item = LogItem(
102
+ log=self,
103
+ no=len(self.logs),
104
+ type=type,
105
+ heading=heading or "",
106
+ content=content or "",
107
+ kvps=kvps,
108
+ temp=temp or False,
109
+ id=id, # Pass id to LogItem
110
+ )
111
+ self.logs.append(item)
112
+ self.updates += [item.no]
113
+ if heading and item.no >= self.progress_no:
114
+ self.progress = heading
115
+ self.progress_no = item.no
116
+ return item
117
+
118
+ def update_item(
119
+ self,
120
+ no: int,
121
+ type: str | None = None,
122
+ heading: str | None = None,
123
+ content: str | None = None,
124
+ kvps: dict | None = None,
125
+ temp: bool | None = None,
126
+ **kwargs,
127
+ ):
128
+ item = self.logs[no]
129
+ if type is not None:
130
+ item.type = type
131
+ if heading is not None:
132
+ item.heading = heading
133
+ if no >= self.progress_no:
134
+ self.progress = heading
135
+ self.progress_no = no
136
+ if content is not None:
137
+ item.content = content
138
+ if kvps is not None:
139
+ item.kvps = OrderedDict(kvps) # Use OrderedDict to keep the order
140
+
141
+ if temp is not None:
142
+ item.temp = temp
143
+
144
+ if kwargs:
145
+ if item.kvps is None:
146
+ item.kvps = OrderedDict() # Ensure kvps is an OrderedDict
147
+ for k, v in kwargs.items():
148
+ item.kvps[k] = v
149
+
150
+ self.updates += [item.no]
151
+
152
+ def set_progress(self, progress: str):
153
+ self.progress = progress
154
+ self.progress_no = len(self.logs)
155
+
156
+ def output(self, start=None, end=None):
157
+ if start is None:
158
+ start = 0
159
+ if end is None:
160
+ end = len(self.updates)
161
+
162
+ out = []
163
+ seen = set()
164
+ for update in self.updates[start:end]:
165
+ if update not in seen:
166
+ out.append(self.logs[update].output())
167
+ seen.add(update)
168
+
169
+ return out
170
+
171
+ def reset(self):
172
+ self.guid = str(uuid.uuid4())
173
+ self.updates = []
174
+ self.logs = []
175
+ self.progress = ""
176
+ self.progress_no = 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.65,
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,