pycityagent 2.0.0a65__cp312-cp312-macosx_11_0_arm64.whl → 2.0.0a67__cp312-cp312-macosx_11_0_arm64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pycityagent/agent/agent.py +157 -57
- pycityagent/agent/agent_base.py +316 -43
- pycityagent/cityagent/bankagent.py +49 -9
- pycityagent/cityagent/blocks/__init__.py +1 -2
- pycityagent/cityagent/blocks/cognition_block.py +54 -31
- pycityagent/cityagent/blocks/dispatcher.py +22 -17
- pycityagent/cityagent/blocks/economy_block.py +46 -32
- pycityagent/cityagent/blocks/mobility_block.py +209 -105
- pycityagent/cityagent/blocks/needs_block.py +101 -54
- pycityagent/cityagent/blocks/other_block.py +42 -33
- pycityagent/cityagent/blocks/plan_block.py +59 -42
- pycityagent/cityagent/blocks/social_block.py +167 -126
- pycityagent/cityagent/blocks/utils.py +13 -6
- pycityagent/cityagent/firmagent.py +17 -35
- pycityagent/cityagent/governmentagent.py +3 -3
- pycityagent/cityagent/initial.py +79 -49
- pycityagent/cityagent/memory_config.py +123 -94
- pycityagent/cityagent/message_intercept.py +0 -4
- pycityagent/cityagent/metrics.py +41 -0
- pycityagent/cityagent/nbsagent.py +24 -36
- pycityagent/cityagent/societyagent.py +9 -4
- pycityagent/cli/wrapper.py +2 -2
- pycityagent/economy/econ_client.py +407 -81
- pycityagent/environment/__init__.py +0 -3
- pycityagent/environment/sim/__init__.py +0 -3
- pycityagent/environment/sim/aoi_service.py +2 -2
- pycityagent/environment/sim/client.py +3 -31
- pycityagent/environment/sim/clock_service.py +2 -2
- pycityagent/environment/sim/lane_service.py +8 -8
- pycityagent/environment/sim/light_service.py +8 -8
- pycityagent/environment/sim/pause_service.py +9 -10
- pycityagent/environment/sim/person_service.py +20 -20
- pycityagent/environment/sim/road_service.py +2 -2
- pycityagent/environment/sim/sim_env.py +21 -5
- pycityagent/environment/sim/social_service.py +4 -4
- pycityagent/environment/simulator.py +249 -27
- pycityagent/environment/utils/__init__.py +2 -2
- pycityagent/environment/utils/geojson.py +2 -2
- pycityagent/environment/utils/grpc.py +4 -4
- pycityagent/environment/utils/map_utils.py +2 -2
- pycityagent/llm/embeddings.py +147 -28
- pycityagent/llm/llm.py +178 -111
- pycityagent/llm/llmconfig.py +5 -0
- pycityagent/llm/utils.py +4 -0
- pycityagent/memory/__init__.py +0 -4
- pycityagent/memory/const.py +2 -2
- pycityagent/memory/faiss_query.py +140 -61
- pycityagent/memory/memory.py +394 -91
- pycityagent/memory/memory_base.py +140 -34
- pycityagent/memory/profile.py +13 -13
- pycityagent/memory/self_define.py +13 -13
- pycityagent/memory/state.py +14 -14
- pycityagent/message/message_interceptor.py +253 -3
- pycityagent/message/messager.py +133 -6
- pycityagent/metrics/mlflow_client.py +47 -4
- pycityagent/pycityagent-sim +0 -0
- pycityagent/pycityagent-ui +0 -0
- pycityagent/simulation/__init__.py +3 -2
- pycityagent/simulation/agentgroup.py +150 -54
- pycityagent/simulation/simulation.py +276 -66
- pycityagent/survey/manager.py +45 -3
- pycityagent/survey/models.py +42 -2
- pycityagent/tools/__init__.py +1 -2
- pycityagent/tools/tool.py +93 -69
- pycityagent/utils/avro_schema.py +2 -2
- pycityagent/utils/parsers/code_block_parser.py +1 -1
- pycityagent/utils/parsers/json_parser.py +2 -2
- pycityagent/utils/parsers/parser_base.py +2 -2
- pycityagent/workflow/block.py +64 -13
- pycityagent/workflow/prompt.py +31 -23
- pycityagent/workflow/trigger.py +91 -24
- {pycityagent-2.0.0a65.dist-info → pycityagent-2.0.0a67.dist-info}/METADATA +2 -2
- pycityagent-2.0.0a67.dist-info/RECORD +97 -0
- pycityagent/environment/interact/__init__.py +0 -0
- pycityagent/environment/interact/interact.py +0 -198
- pycityagent/environment/message/__init__.py +0 -0
- pycityagent/environment/sence/__init__.py +0 -0
- pycityagent/environment/sence/static.py +0 -416
- pycityagent/environment/sidecar/__init__.py +0 -8
- pycityagent/environment/sidecar/sidecarv2.py +0 -109
- pycityagent/environment/sim/economy_services.py +0 -192
- pycityagent/metrics/utils/const.py +0 -0
- pycityagent-2.0.0a65.dist-info/RECORD +0 -105
- {pycityagent-2.0.0a65.dist-info → pycityagent-2.0.0a67.dist-info}/LICENSE +0 -0
- {pycityagent-2.0.0a65.dist-info → pycityagent-2.0.0a67.dist-info}/WHEEL +0 -0
- {pycityagent-2.0.0a65.dist-info → pycityagent-2.0.0a67.dist-info}/entry_points.txt +0 -0
- {pycityagent-2.0.0a65.dist-info → pycityagent-2.0.0a67.dist-info}/top_level.txt +0 -0
pycityagent/memory/memory.py
CHANGED
@@ -21,7 +21,7 @@ logger = logging.getLogger("pycityagent")
|
|
21
21
|
|
22
22
|
|
23
23
|
class MemoryTag(str, Enum):
|
24
|
-
"""
|
24
|
+
"""Memory tag enumeration class"""
|
25
25
|
|
26
26
|
MOBILITY = "mobility"
|
27
27
|
SOCIAL = "social"
|
@@ -33,7 +33,18 @@ class MemoryTag(str, Enum):
|
|
33
33
|
|
34
34
|
@dataclass
|
35
35
|
class MemoryNode:
|
36
|
-
"""
|
36
|
+
"""
|
37
|
+
A data class representing a memory node.
|
38
|
+
|
39
|
+
- **Attributes**:
|
40
|
+
- `tag`: The tag associated with the memory node.
|
41
|
+
- `day`: Day of the event or memory.
|
42
|
+
- `t`: Time stamp or order.
|
43
|
+
- `location`: Location where the event occurred.
|
44
|
+
- `description`: Description of the memory.
|
45
|
+
- `cognition_id`: ID related to cognitive memory (optional).
|
46
|
+
- `id`: Unique ID for this memory node (optional).
|
47
|
+
"""
|
37
48
|
|
38
49
|
tag: MemoryTag
|
39
50
|
day: int
|
@@ -45,9 +56,26 @@ class MemoryNode:
|
|
45
56
|
|
46
57
|
|
47
58
|
class StreamMemory:
|
48
|
-
"""
|
59
|
+
"""
|
60
|
+
A class used to store and manage time-ordered stream information.
|
61
|
+
|
62
|
+
- **Attributes**:
|
63
|
+
- `_memories`: A deque to store memory nodes with a maximum length limit.
|
64
|
+
- `_memory_id_counter`: An internal counter to generate unique IDs for each new memory node.
|
65
|
+
- `_faiss_query`: The Faiss query object for search functionality.
|
66
|
+
- `_embedding_model`: The embedding model object for vectorizing text or other data.
|
67
|
+
- `_agent_id`: Identifier for the agent owning these memories.
|
68
|
+
- `_status_memory`: The status memory object.
|
69
|
+
- `_simulator`: The simulator object.
|
70
|
+
"""
|
49
71
|
|
50
72
|
def __init__(self, max_len: int = 1000):
|
73
|
+
"""
|
74
|
+
Initialize an instance of StreamMemory.
|
75
|
+
|
76
|
+
- **Args**:
|
77
|
+
- `max_len` (int): Maximum length of the deque. Default is 1000.
|
78
|
+
"""
|
51
79
|
self._memories: deque = deque(maxlen=max_len) # 限制最大存储量
|
52
80
|
self._memory_id_counter: int = 0 # 用于生成唯一ID
|
53
81
|
self._faiss_query = None
|
@@ -60,6 +88,12 @@ class StreamMemory:
|
|
60
88
|
def faiss_query(
|
61
89
|
self,
|
62
90
|
) -> FaissQuery:
|
91
|
+
"""
|
92
|
+
Get the Faiss query object.
|
93
|
+
|
94
|
+
- **Returns**:
|
95
|
+
- `FaissQuery`: Instance of the Faiss query object.
|
96
|
+
"""
|
63
97
|
assert self._faiss_query is not None
|
64
98
|
return self._faiss_query
|
65
99
|
|
@@ -67,26 +101,64 @@ class StreamMemory:
|
|
67
101
|
def status_memory(
|
68
102
|
self,
|
69
103
|
):
|
104
|
+
"""
|
105
|
+
Get the status memory object.
|
106
|
+
|
107
|
+
- **Returns**:
|
108
|
+
- `StatusMemory`: Instance of the status memory object.
|
109
|
+
"""
|
70
110
|
assert self._status_memory is not None
|
71
111
|
return self._status_memory
|
72
112
|
|
73
113
|
def set_simulator(self, simulator):
|
114
|
+
"""
|
115
|
+
Set the simulator object.
|
116
|
+
|
117
|
+
- **Args**:
|
118
|
+
- `simulator` (Simulator): Simulator object.
|
119
|
+
"""
|
74
120
|
self._simulator = simulator
|
75
121
|
|
76
122
|
def set_status_memory(self, status_memory):
|
123
|
+
"""
|
124
|
+
Set the status memory object.
|
125
|
+
|
126
|
+
- **Args**:
|
127
|
+
- `status_memory` (StatusMemory): Status memory object.
|
128
|
+
"""
|
77
129
|
self._status_memory = status_memory
|
78
130
|
|
79
131
|
def set_search_components(self, faiss_query, embedding_model):
|
80
|
-
"""
|
132
|
+
"""
|
133
|
+
Set the components required for search functionality.
|
134
|
+
|
135
|
+
- **Args**:
|
136
|
+
- `faiss_query` (Any): Faiss query object.
|
137
|
+
- `embedding_model` (Any): Embedding model object.
|
138
|
+
"""
|
81
139
|
self._faiss_query = faiss_query
|
82
140
|
self._embedding_model = embedding_model
|
83
141
|
|
84
142
|
def set_agent_id(self, agent_id: int):
|
85
|
-
"""
|
143
|
+
"""
|
144
|
+
Set the agent ID.
|
145
|
+
|
146
|
+
- **Args**:
|
147
|
+
- `agent_id` (int): Agent ID.
|
148
|
+
"""
|
86
149
|
self._agent_id = agent_id
|
87
150
|
|
88
151
|
async def _add_memory(self, tag: MemoryTag, description: str) -> int:
|
89
|
-
"""
|
152
|
+
"""
|
153
|
+
A generic method for adding a memory node and returning the memory node ID.
|
154
|
+
|
155
|
+
- **Args**:
|
156
|
+
- `tag` (MemoryTag): The tag associated with the memory node.
|
157
|
+
- `description` (str): Description of the memory.
|
158
|
+
|
159
|
+
- **Returns**:
|
160
|
+
- `int`: The unique ID of the newly added memory node.
|
161
|
+
"""
|
90
162
|
if self._simulator is not None:
|
91
163
|
day = int(await self._simulator.get_simulator_day())
|
92
164
|
t = int(await self._simulator.get_time())
|
@@ -129,31 +201,87 @@ class StreamMemory:
|
|
129
201
|
return current_id
|
130
202
|
|
131
203
|
async def add_cognition(self, description: str) -> int:
|
132
|
-
"""
|
204
|
+
"""
|
205
|
+
Add a cognition memory node.
|
206
|
+
|
207
|
+
- **Args**:
|
208
|
+
- `description` (str): Description of the cognition memory.
|
209
|
+
|
210
|
+
- **Returns**:
|
211
|
+
- `int`: The unique ID of the newly added cognition memory node.
|
212
|
+
"""
|
133
213
|
return await self._add_memory(MemoryTag.COGNITION, description)
|
134
214
|
|
135
215
|
async def add_social(self, description: str) -> int:
|
136
|
-
"""
|
216
|
+
"""
|
217
|
+
Add a social memory node.
|
218
|
+
|
219
|
+
- **Args**:
|
220
|
+
- `description` (str): Description of the social memory.
|
221
|
+
|
222
|
+
- **Returns**:
|
223
|
+
- `int`: The unique ID of the newly added social memory node.
|
224
|
+
"""
|
137
225
|
return await self._add_memory(MemoryTag.SOCIAL, description)
|
138
226
|
|
139
227
|
async def add_economy(self, description: str) -> int:
|
140
|
-
"""
|
228
|
+
"""
|
229
|
+
Add an economy memory node.
|
230
|
+
|
231
|
+
- **Args**:
|
232
|
+
- `description` (str): Description of the economy memory.
|
233
|
+
|
234
|
+
- **Returns**:
|
235
|
+
- `int`: The unique ID of the newly added economy memory node.
|
236
|
+
"""
|
141
237
|
return await self._add_memory(MemoryTag.ECONOMY, description)
|
142
238
|
|
143
239
|
async def add_mobility(self, description: str) -> int:
|
144
|
-
"""
|
240
|
+
"""
|
241
|
+
Add a mobility memory node.
|
242
|
+
|
243
|
+
- **Args**:
|
244
|
+
- `description` (str): Description of the mobility memory.
|
245
|
+
|
246
|
+
- **Returns**:
|
247
|
+
- `int`: The unique ID of the newly added mobility memory node.
|
248
|
+
"""
|
145
249
|
return await self._add_memory(MemoryTag.MOBILITY, description)
|
146
250
|
|
147
251
|
async def add_event(self, description: str) -> int:
|
148
|
-
"""
|
252
|
+
"""
|
253
|
+
Add an event memory node.
|
254
|
+
|
255
|
+
- **Args**:
|
256
|
+
- `description` (str): Description of the event memory.
|
257
|
+
|
258
|
+
- **Returns**:
|
259
|
+
- `int`: The unique ID of the newly added event memory node.
|
260
|
+
"""
|
149
261
|
return await self._add_memory(MemoryTag.EVENT, description)
|
150
262
|
|
151
263
|
async def add_other(self, description: str) -> int:
|
152
|
-
"""
|
264
|
+
"""
|
265
|
+
Add an other type memory node.
|
266
|
+
|
267
|
+
- **Args**:
|
268
|
+
- `description` (str): Description of the other type memory.
|
269
|
+
|
270
|
+
- **Returns**:
|
271
|
+
- `int`: The unique ID of the newly added other type memory node.
|
272
|
+
"""
|
153
273
|
return await self._add_memory(MemoryTag.OTHER, description)
|
154
274
|
|
155
|
-
async def get_related_cognition(self, memory_id: int) ->
|
156
|
-
"""
|
275
|
+
async def get_related_cognition(self, memory_id: int) -> Union[MemoryNode, None]:
|
276
|
+
"""
|
277
|
+
Retrieve the related cognition memory node by its ID.
|
278
|
+
|
279
|
+
- **Args**:
|
280
|
+
- `memory_id` (int): The ID of the memory to find related cognition for.
|
281
|
+
|
282
|
+
- **Returns**:
|
283
|
+
- `Optional[MemoryNode]`: The related cognition memory node, if found; otherwise, None.
|
284
|
+
"""
|
157
285
|
for memory in self._memories:
|
158
286
|
if memory.cognition_id == memory_id:
|
159
287
|
for cognition_memory in self._memories:
|
@@ -165,7 +293,15 @@ class StreamMemory:
|
|
165
293
|
return None
|
166
294
|
|
167
295
|
async def format_memory(self, memories: list[MemoryNode]) -> str:
|
168
|
-
"""
|
296
|
+
"""
|
297
|
+
Format a list of memory nodes into a readable string representation.
|
298
|
+
|
299
|
+
- **Args**:
|
300
|
+
- `memories` (list[MemoryNode]): List of MemoryNode objects to format.
|
301
|
+
|
302
|
+
- **Returns**:
|
303
|
+
- `str`: A formatted string containing the details of each memory node.
|
304
|
+
"""
|
169
305
|
formatted_results = []
|
170
306
|
for memory in memories:
|
171
307
|
memory_tag = memory.tag
|
@@ -215,14 +351,18 @@ class StreamMemory:
|
|
215
351
|
day_range: Optional[tuple[int, int]] = None, # 新增参数
|
216
352
|
time_range: Optional[tuple[int, int]] = None, # 新增参数
|
217
353
|
) -> str:
|
218
|
-
"""
|
354
|
+
"""
|
355
|
+
Search stream memory with optional filters and return formatted results.
|
219
356
|
|
220
|
-
Args
|
221
|
-
query:
|
222
|
-
tag
|
223
|
-
top_k: Number of
|
224
|
-
day_range
|
225
|
-
time_range
|
357
|
+
- **Args**:
|
358
|
+
- `query` (str): The text to use for searching.
|
359
|
+
- `tag` (Optional[MemoryTag], optional): Filter memories by this tag. Defaults to None.
|
360
|
+
- `top_k` (int, optional): Number of top relevant memories to return. Defaults to 3.
|
361
|
+
- `day_range` (Optional[tuple[int, int]], optional): Tuple of start and end days for filtering. Defaults to None.
|
362
|
+
- `time_range` (Optional[tuple[int, int]], optional): Tuple of start and end times for filtering. Defaults to None.
|
363
|
+
|
364
|
+
- **Returns**:
|
365
|
+
- `str`: Formatted string of the search results.
|
226
366
|
"""
|
227
367
|
if not self._embedding_model or not self._faiss_query:
|
228
368
|
return "Search components not initialized"
|
@@ -297,12 +437,12 @@ class StreamMemory:
|
|
297
437
|
) -> str:
|
298
438
|
"""Search all memory events from today
|
299
439
|
|
300
|
-
Args
|
440
|
+
- **Args**:
|
301
441
|
query: Optional query text, returns all memories of the day if empty
|
302
442
|
tag: Optional memory tag for filtering specific types of memories
|
303
443
|
top_k: Number of most relevant memories to return, defaults to 100
|
304
444
|
|
305
|
-
Returns
|
445
|
+
- **Returns**:
|
306
446
|
str: Formatted text of today's memories
|
307
447
|
"""
|
308
448
|
if self._simulator is None:
|
@@ -318,11 +458,12 @@ class StreamMemory:
|
|
318
458
|
async def add_cognition_to_memory(
|
319
459
|
self, memory_id: Union[int, list[int]], cognition: str
|
320
460
|
) -> None:
|
321
|
-
"""
|
461
|
+
"""
|
462
|
+
Add cognition to existing memory nodes.
|
322
463
|
|
323
|
-
Args
|
324
|
-
memory_id:
|
325
|
-
cognition:
|
464
|
+
- **Args**:
|
465
|
+
- `memory_id` (Union[int, list[int]]): ID or list of IDs of the memories to which cognition will be added.
|
466
|
+
- `cognition` (str): Description of the cognition to add.
|
326
467
|
"""
|
327
468
|
# 将单个ID转换为列表以统一处理
|
328
469
|
memory_ids = [memory_id] if isinstance(memory_id, int) else memory_id
|
@@ -330,7 +471,7 @@ class StreamMemory:
|
|
330
471
|
# 找到所有对应的记忆
|
331
472
|
target_memories = []
|
332
473
|
for memory in self._memories:
|
333
|
-
if id
|
474
|
+
if memory.id in memory_ids:
|
334
475
|
target_memories.append(memory)
|
335
476
|
|
336
477
|
if not target_memories:
|
@@ -344,16 +485,29 @@ class StreamMemory:
|
|
344
485
|
target_memory.cognition_id = cognition_id
|
345
486
|
|
346
487
|
async def get_all(self) -> list[MemoryNode]:
|
347
|
-
"""
|
488
|
+
"""
|
489
|
+
Retrieve all stream memory nodes.
|
490
|
+
|
491
|
+
- **Returns**:
|
492
|
+
- `list[MemoryNode]`: List of all MemoryNode objects.
|
493
|
+
"""
|
348
494
|
return list(self._memories)
|
349
495
|
|
350
496
|
|
351
497
|
class StatusMemory:
|
352
|
-
"""
|
498
|
+
"""Combine existing three types of memories into a single interface."""
|
353
499
|
|
354
500
|
def __init__(
|
355
501
|
self, profile: ProfileMemory, state: StateMemory, dynamic: DynamicMemory
|
356
502
|
):
|
503
|
+
"""
|
504
|
+
Initialize the StatusMemory with three types of memory.
|
505
|
+
|
506
|
+
- **Args**:
|
507
|
+
- `profile`: Profile memory instance.
|
508
|
+
- `state`: State memory instance.
|
509
|
+
- `dynamic`: Dynamic memory instance.
|
510
|
+
"""
|
357
511
|
self.profile = profile
|
358
512
|
self.state = state
|
359
513
|
self.dynamic = dynamic
|
@@ -371,14 +525,16 @@ class StatusMemory:
|
|
371
525
|
def faiss_query(
|
372
526
|
self,
|
373
527
|
) -> FaissQuery:
|
528
|
+
"""Get the Faiss query component."""
|
374
529
|
assert self._faiss_query is not None
|
375
530
|
return self._faiss_query
|
376
531
|
|
377
532
|
def set_simulator(self, simulator):
|
533
|
+
"""Set the simulator for this status memory."""
|
378
534
|
self._simulator = simulator
|
379
535
|
|
380
536
|
async def initialize_embeddings(self) -> None:
|
381
|
-
"""
|
537
|
+
"""Initialize embeddings for all fields that require them."""
|
382
538
|
if not self._embedding_model or not self._faiss_query:
|
383
539
|
logger.warning(
|
384
540
|
"Search components not initialized, skipping embeddings initialization"
|
@@ -429,7 +585,7 @@ class StatusMemory:
|
|
429
585
|
self._embedding_field_to_doc_id[key] = doc_ids[0]
|
430
586
|
|
431
587
|
def _get_memory_type_by_key(self, key: str) -> str:
|
432
|
-
"""
|
588
|
+
"""Determine the type of memory based on the key name."""
|
433
589
|
try:
|
434
590
|
if key in self.profile.__dict__:
|
435
591
|
return "profile"
|
@@ -441,27 +597,41 @@ class StatusMemory:
|
|
441
597
|
return "dynamic"
|
442
598
|
|
443
599
|
def set_search_components(self, faiss_query, embedding_model):
|
444
|
-
"""
|
600
|
+
"""Set the search components for this status memory."""
|
445
601
|
self._faiss_query = faiss_query
|
446
602
|
self._embedding_model = embedding_model
|
447
603
|
|
448
604
|
def set_agent_id(self, agent_id: int):
|
449
|
-
"""
|
605
|
+
"""
|
606
|
+
Set the agent ID.
|
607
|
+
|
608
|
+
- **Args**:
|
609
|
+
- `agent_id` (int): Agent ID.
|
610
|
+
"""
|
450
611
|
self._agent_id = agent_id
|
451
612
|
|
452
613
|
def set_semantic_templates(self, templates: Dict[str, str]):
|
453
|
-
"""
|
614
|
+
"""
|
615
|
+
Set the semantic templates for generating embedding text.
|
454
616
|
|
455
|
-
Args
|
456
|
-
templates
|
617
|
+
- **Args**:
|
618
|
+
- `templates` (Dict[str, str]): A dictionary of key-value pairs where keys are field names and values are template strings.
|
457
619
|
"""
|
458
620
|
self._semantic_templates = templates
|
459
621
|
|
460
622
|
def _generate_semantic_text(self, key: str, value: Any) -> str:
|
461
|
-
"""
|
623
|
+
"""
|
624
|
+
Generate semantic text for a given key and value.
|
625
|
+
|
626
|
+
If a custom template exists for the key, it uses that template;
|
627
|
+
otherwise, it uses a default template "Your {key} is {value}".
|
628
|
+
|
629
|
+
- **Args**:
|
630
|
+
- `key` (str): The name of the field.
|
631
|
+
- `value` (Any): The value associated with the field.
|
462
632
|
|
463
|
-
|
464
|
-
|
633
|
+
- **Returns**:
|
634
|
+
- `str`: The generated semantic text.
|
465
635
|
"""
|
466
636
|
if key in self._semantic_templates:
|
467
637
|
return self._semantic_templates[key].format(value)
|
@@ -471,15 +641,16 @@ class StatusMemory:
|
|
471
641
|
async def search(
|
472
642
|
self, query: str, top_k: int = 3, filter: Optional[dict] = None
|
473
643
|
) -> str:
|
474
|
-
"""
|
644
|
+
"""
|
645
|
+
Search for relevant memories based on the provided query.
|
475
646
|
|
476
|
-
Args
|
477
|
-
query:
|
478
|
-
top_k:
|
479
|
-
filter (dict, optional):
|
647
|
+
- **Args**:
|
648
|
+
- `query` (str): The text query to search for.
|
649
|
+
- `top_k` (int, optional): Number of top relevant memories to return. Defaults to 3.
|
650
|
+
- `filter` (Optional[dict], optional): Additional filters for the search. Defaults to None.
|
480
651
|
|
481
|
-
Returns
|
482
|
-
str
|
652
|
+
- **Returns**:
|
653
|
+
- `str`: Formatted string of the search results.
|
483
654
|
"""
|
484
655
|
if not self._embedding_model:
|
485
656
|
return "Embedding model not initialized"
|
@@ -504,31 +675,47 @@ class StatusMemory:
|
|
504
675
|
return "\n".join(formatted_results)
|
505
676
|
|
506
677
|
def set_embedding_fields(self, embedding_fields: Dict[str, bool]):
|
507
|
-
"""
|
678
|
+
"""
|
679
|
+
Set which fields require embeddings.
|
680
|
+
|
681
|
+
- **Args**:
|
682
|
+
- `embedding_fields` (Dict[str, bool]): Dictionary indicating whether each field should be embedded.
|
683
|
+
"""
|
508
684
|
self._embedding_fields = embedding_fields
|
509
685
|
|
510
686
|
def should_embed(self, key: str) -> bool:
|
511
|
-
"""
|
687
|
+
"""
|
688
|
+
Determine if a given field requires an embedding.
|
689
|
+
|
690
|
+
- **Args**:
|
691
|
+
- `key` (str): The name of the field.
|
692
|
+
|
693
|
+
- **Returns**:
|
694
|
+
- `bool`: True if the field should be embedded, False otherwise.
|
695
|
+
"""
|
512
696
|
return self._embedding_fields.get(key, False)
|
513
697
|
|
514
698
|
@lock_decorator
|
515
699
|
async def get(
|
516
700
|
self,
|
517
701
|
key: Any,
|
702
|
+
default_value: Optional[Any] = None,
|
518
703
|
mode: Union[Literal["read only"], Literal["read and write"]] = "read only",
|
519
704
|
) -> Any:
|
520
|
-
"""
|
705
|
+
"""
|
706
|
+
Retrieve a value from the memory.
|
521
707
|
|
522
|
-
Args
|
523
|
-
key:
|
524
|
-
|
708
|
+
- **Args**:
|
709
|
+
- `key` (Any): The key to retrieve.
|
710
|
+
- `default_value` (Optional[Any], optional): Default value if the key is not found. Defaults to None.
|
711
|
+
- `mode` (Union[Literal["read only"], Literal["read and write"]], optional): Access mode for the value. Defaults to "read only".
|
525
712
|
|
526
|
-
Returns
|
527
|
-
|
713
|
+
- **Returns**:
|
714
|
+
- `Any`: The retrieved value or the default value if the key is not found.
|
528
715
|
|
529
|
-
Raises
|
530
|
-
ValueError
|
531
|
-
KeyError
|
716
|
+
- **Raises**:
|
717
|
+
- `ValueError`: If an invalid mode is provided.
|
718
|
+
- `KeyError`: If the key is not found in any of the memory sections and no default value is provided.
|
532
719
|
"""
|
533
720
|
if mode == "read only":
|
534
721
|
process_func = deepcopy
|
@@ -543,7 +730,10 @@ class StatusMemory:
|
|
543
730
|
return process_func(value)
|
544
731
|
except KeyError:
|
545
732
|
continue
|
546
|
-
|
733
|
+
if default_value is None:
|
734
|
+
raise KeyError(f"No attribute `{key}` in memories!")
|
735
|
+
else:
|
736
|
+
return default_value
|
547
737
|
|
548
738
|
@lock_decorator
|
549
739
|
async def update(
|
@@ -554,7 +744,20 @@ class StatusMemory:
|
|
554
744
|
store_snapshot: bool = False,
|
555
745
|
protect_llm_read_only_fields: bool = True,
|
556
746
|
) -> None:
|
557
|
-
"""
|
747
|
+
"""
|
748
|
+
Update a value in the memory and refresh embeddings if necessary.
|
749
|
+
|
750
|
+
- **Args**:
|
751
|
+
- `key` (Any): The key to update.
|
752
|
+
- `value` (Any): The new value to set.
|
753
|
+
- `mode` (Union[Literal["replace"], Literal["merge"]], optional): Update mode. Defaults to "replace".
|
754
|
+
- `store_snapshot` (bool, optional): Whether to store a snapshot. Defaults to False.
|
755
|
+
- `protect_llm_read_only_fields` (bool, optional): Whether to protect certain fields from being updated. Defaults to True.
|
756
|
+
|
757
|
+
- **Raises**:
|
758
|
+
- `ValueError`: If an invalid update mode is provided.
|
759
|
+
- `KeyError`: If the key is not found in any of the memory sections.
|
760
|
+
"""
|
558
761
|
if protect_llm_read_only_fields:
|
559
762
|
if any(key in _attrs for _attrs in [STATE_ATTRIBUTES]):
|
560
763
|
logger.warning(f"Trying to write protected key `{key}`!")
|
@@ -626,7 +829,15 @@ class StatusMemory:
|
|
626
829
|
raise KeyError(f"No attribute `{key}` in memories!")
|
627
830
|
|
628
831
|
def _get_memory_type(self, mem: Any) -> str:
|
629
|
-
"""
|
832
|
+
"""
|
833
|
+
Determine the type of memory.
|
834
|
+
|
835
|
+
- **Args**:
|
836
|
+
- `mem` (Any): The memory instance to check.
|
837
|
+
|
838
|
+
- **Returns**:
|
839
|
+
- `str`: The type of memory ("state", "profile", or "dynamic").
|
840
|
+
"""
|
630
841
|
if mem is self.state:
|
631
842
|
return "state"
|
632
843
|
elif mem is self.profile:
|
@@ -636,7 +847,13 @@ class StatusMemory:
|
|
636
847
|
|
637
848
|
@lock_decorator
|
638
849
|
async def add_watcher(self, key: str, callback: Callable) -> None:
|
639
|
-
"""
|
850
|
+
"""
|
851
|
+
Add a watcher for value changes on a specific key.
|
852
|
+
|
853
|
+
- **Args**:
|
854
|
+
- `key` (str): The key to watch.
|
855
|
+
- `callback` (Callable): The function to call when the watched key's value changes.
|
856
|
+
"""
|
640
857
|
if key not in self.watchers:
|
641
858
|
self.watchers[key] = []
|
642
859
|
self.watchers[key].append(callback)
|
@@ -645,10 +862,10 @@ class StatusMemory:
|
|
645
862
|
self,
|
646
863
|
) -> tuple[Sequence[dict], Sequence[dict], Sequence[dict]]:
|
647
864
|
"""
|
648
|
-
|
865
|
+
Export the current state of all memory sections.
|
649
866
|
|
650
|
-
Returns
|
651
|
-
|
867
|
+
- **Returns**:
|
868
|
+
- `Tuple[Sequence[Dict], Sequence[Dict], Sequence[Dict]]`: A tuple containing the exported data from profile, state, and dynamic memory sections.
|
652
869
|
"""
|
653
870
|
return (
|
654
871
|
await self.profile.export(),
|
@@ -662,11 +879,11 @@ class StatusMemory:
|
|
662
879
|
reset_memory: bool = True,
|
663
880
|
) -> None:
|
664
881
|
"""
|
665
|
-
|
882
|
+
Load snapshot memories into all sections.
|
666
883
|
|
667
|
-
Args
|
668
|
-
snapshots (
|
669
|
-
reset_memory (bool): Whether to reset previous memory.
|
884
|
+
- **Args**:
|
885
|
+
- `snapshots` (Tuple[Sequence[Dict], Sequence[Dict], Sequence[Dict]]): The exported snapshots to load.
|
886
|
+
- `reset_memory` (bool, optional): Whether to reset previous memory. Defaults to True.
|
670
887
|
"""
|
671
888
|
_profile_snapshot, _state_snapshot, _dynamic_snapshot = snapshots
|
672
889
|
for _snapshot, _mem in zip(
|
@@ -681,10 +898,14 @@ class Memory:
|
|
681
898
|
"""
|
682
899
|
A class to manage different types of memory (state, profile, dynamic).
|
683
900
|
|
684
|
-
Attributes
|
685
|
-
_state (StateMemory): Stores state-related data.
|
686
|
-
_profile (ProfileMemory): Stores profile-related data.
|
687
|
-
_dynamic (DynamicMemory): Stores dynamically configured data.
|
901
|
+
- **Attributes**:
|
902
|
+
- `_state` (`StateMemory`): Stores state-related data.
|
903
|
+
- `_profile` (`ProfileMemory`): Stores profile-related data.
|
904
|
+
- `_dynamic` (`DynamicMemory`): Stores dynamically configured data.
|
905
|
+
|
906
|
+
- **Methods**:
|
907
|
+
- `set_search_components`: Sets the search components for stream and status memory.
|
908
|
+
|
688
909
|
"""
|
689
910
|
|
690
911
|
def __init__(
|
@@ -699,21 +920,27 @@ class Memory:
|
|
699
920
|
"""
|
700
921
|
Initializes the Memory with optional configuration.
|
701
922
|
|
702
|
-
|
703
|
-
|
704
|
-
|
705
|
-
|
706
|
-
|
707
|
-
|
708
|
-
|
709
|
-
|
923
|
+
- **Description**:
|
924
|
+
- Sets up the memory management system by initializing different memory types (state, profile, dynamic)
|
925
|
+
and configuring them based on provided parameters. Also initializes watchers and locks for thread-safe operations.
|
926
|
+
|
927
|
+
- **Args**:
|
928
|
+
- `config` (Optional[dict[Any, Any]], optional):
|
929
|
+
Configuration dictionary for dynamic memory, where keys are field names and values can be tuples or callables.
|
930
|
+
Defaults to None.
|
931
|
+
- `profile` (Optional[dict[Any, Any]], optional): Dictionary for profile attributes.
|
932
|
+
Defaults to None.
|
933
|
+
- `base` (Optional[dict[Any, Any]], optional): Dictionary for base attributes from City Simulator.
|
934
|
+
Defaults to None.
|
935
|
+
- `activate_timestamp` (bool): Flag to enable timestamp storage in MemoryUnit.
|
936
|
+
Defaults to False.
|
937
|
+
- `embedding_model` (Optional[Embeddings]): Embedding model used for memory search.
|
710
938
|
Defaults to None.
|
711
|
-
|
712
|
-
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
faiss_query (FaissQuery): The faiss_query of the agent. Defaults to None.
|
939
|
+
- `faiss_query` (Optional[FaissQuery]): Faiss query object for the agent.
|
940
|
+
Defaults to None.
|
941
|
+
|
942
|
+
- **Returns**:
|
943
|
+
- `None`
|
717
944
|
"""
|
718
945
|
self.watchers: dict[str, list[Callable]] = {}
|
719
946
|
self._lock = asyncio.Lock()
|
@@ -856,6 +1083,19 @@ class Memory:
|
|
856
1083
|
faiss_query: FaissQuery,
|
857
1084
|
embedding_model: Embeddings,
|
858
1085
|
):
|
1086
|
+
"""
|
1087
|
+
Set the search components for stream and status memory.
|
1088
|
+
|
1089
|
+
- **Description**:
|
1090
|
+
- Updates the embedding model and faiss query for both stream and status memory, allowing for new searches to use updated models.
|
1091
|
+
|
1092
|
+
- **Args**:
|
1093
|
+
- `faiss_query` (`FaissQuery`): The new faiss query component.
|
1094
|
+
- `embedding_model` (`Embeddings`): The new embedding model component.
|
1095
|
+
|
1096
|
+
- **Returns**:
|
1097
|
+
- `None`
|
1098
|
+
"""
|
859
1099
|
self._embedding_model = embedding_model
|
860
1100
|
self._faiss_query = faiss_query
|
861
1101
|
self._stream.set_search_components(faiss_query, embedding_model)
|
@@ -863,13 +1103,34 @@ class Memory:
|
|
863
1103
|
|
864
1104
|
def set_agent_id(self, agent_id: int):
|
865
1105
|
"""
|
866
|
-
Set the
|
1106
|
+
Set the agent ID for the memory management system.
|
1107
|
+
|
1108
|
+
- **Description**:
|
1109
|
+
- Sets the identifier for the agent and propagates this ID to stream and status memory components.
|
1110
|
+
|
1111
|
+
- **Args**:
|
1112
|
+
- `agent_id` (int): Identifier of the agent.
|
1113
|
+
|
1114
|
+
- **Returns**:
|
1115
|
+
- `None`
|
867
1116
|
"""
|
868
1117
|
self._agent_id = agent_id
|
869
1118
|
self._stream.set_agent_id(agent_id)
|
870
1119
|
self._status.set_agent_id(agent_id)
|
871
1120
|
|
872
1121
|
def set_simulator(self, simulator):
|
1122
|
+
"""
|
1123
|
+
Assign a simulator to the memory management system.
|
1124
|
+
|
1125
|
+
- **Description**:
|
1126
|
+
- Sets the simulator for the memory system and passes it on to the stream and status memory components.
|
1127
|
+
|
1128
|
+
- **Args**:
|
1129
|
+
- `simulator`: The simulator object to be used by the memory system.
|
1130
|
+
|
1131
|
+
- **Returns**:
|
1132
|
+
- `None`
|
1133
|
+
"""
|
873
1134
|
self._simulator = simulator
|
874
1135
|
self._stream.set_simulator(simulator)
|
875
1136
|
self._status.set_simulator(simulator)
|
@@ -886,6 +1147,18 @@ class Memory:
|
|
886
1147
|
def embedding_model(
|
887
1148
|
self,
|
888
1149
|
):
|
1150
|
+
"""
|
1151
|
+
Access the embedding model used in the memory system.
|
1152
|
+
|
1153
|
+
- **Description**:
|
1154
|
+
- Property that provides access to the embedding model. Raises an error if accessed before assignment.
|
1155
|
+
|
1156
|
+
- **Raises**:
|
1157
|
+
- `RuntimeError`: If the embedding model has not been set yet.
|
1158
|
+
|
1159
|
+
- **Returns**:
|
1160
|
+
- `Embeddings`: The embedding model instance.
|
1161
|
+
"""
|
889
1162
|
if self._embedding_model is None:
|
890
1163
|
raise RuntimeError(
|
891
1164
|
f"embedding_model before assignment, please `set_embedding_model` first!"
|
@@ -896,6 +1169,18 @@ class Memory:
|
|
896
1169
|
def agent_id(
|
897
1170
|
self,
|
898
1171
|
):
|
1172
|
+
"""
|
1173
|
+
Access the agent ID.
|
1174
|
+
|
1175
|
+
- **Description**:
|
1176
|
+
- Property that provides access to the agent ID. Raises an error if accessed before assignment.
|
1177
|
+
|
1178
|
+
- **Raises**:
|
1179
|
+
- `RuntimeError`: If the agent ID has not been set yet.
|
1180
|
+
|
1181
|
+
- **Returns**:
|
1182
|
+
- `int`: The agent's identifier.
|
1183
|
+
"""
|
899
1184
|
if self._agent_id < 0:
|
900
1185
|
raise RuntimeError(
|
901
1186
|
f"agent_id before assignment, please `set_agent_id` first!"
|
@@ -904,7 +1189,18 @@ class Memory:
|
|
904
1189
|
|
905
1190
|
@property
|
906
1191
|
def faiss_query(self) -> FaissQuery:
|
907
|
-
"""
|
1192
|
+
"""
|
1193
|
+
Access the FaissQuery component.
|
1194
|
+
|
1195
|
+
- **Description**:
|
1196
|
+
- Property that provides access to the FaissQuery component. Raises an error if accessed before assignment.
|
1197
|
+
|
1198
|
+
- **Raises**:
|
1199
|
+
- `RuntimeError`: If the FaissQuery has not been set yet.
|
1200
|
+
|
1201
|
+
- **Returns**:
|
1202
|
+
- `FaissQuery`: The FaissQuery instance.
|
1203
|
+
"""
|
908
1204
|
if self._faiss_query is None:
|
909
1205
|
raise RuntimeError(
|
910
1206
|
f"FaissQuery access before assignment, please `set_faiss_query` first!"
|
@@ -912,5 +1208,12 @@ class Memory:
|
|
912
1208
|
return self._faiss_query
|
913
1209
|
|
914
1210
|
async def initialize_embeddings(self):
|
915
|
-
"""
|
1211
|
+
"""
|
1212
|
+
Initialize embeddings within the status memory.
|
1213
|
+
|
1214
|
+
- **Description**:
|
1215
|
+
- Asynchronously initializes embeddings for the status memory component, which prepares the system for performing searches.
|
1216
|
+
|
1217
|
+
- **Returns**:
|
1218
|
+
"""
|
916
1219
|
await self._status.initialize_embeddings()
|