pycityagent 1.0.0__py3-none-any.whl → 2.0.0a2__py3-none-any.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/__init__.py +7 -3
- pycityagent/agent.py +180 -284
- pycityagent/economy/__init__.py +5 -0
- pycityagent/economy/econ_client.py +307 -0
- pycityagent/environment/__init__.py +7 -0
- pycityagent/environment/interact/interact.py +141 -0
- pycityagent/environment/sence/__init__.py +0 -0
- pycityagent/{brain → environment/sence}/static.py +1 -1
- pycityagent/environment/sidecar/__init__.py +8 -0
- pycityagent/environment/sidecar/sidecarv2.py +109 -0
- pycityagent/environment/sim/__init__.py +29 -0
- pycityagent/environment/sim/aoi_service.py +38 -0
- pycityagent/environment/sim/client.py +126 -0
- pycityagent/environment/sim/clock_service.py +43 -0
- pycityagent/environment/sim/economy_services.py +191 -0
- pycityagent/environment/sim/lane_service.py +110 -0
- pycityagent/environment/sim/light_service.py +120 -0
- pycityagent/environment/sim/person_service.py +294 -0
- pycityagent/environment/sim/road_service.py +38 -0
- pycityagent/environment/sim/sim_env.py +145 -0
- pycityagent/environment/sim/social_service.py +58 -0
- pycityagent/environment/simulator.py +320 -0
- pycityagent/environment/utils/__init__.py +10 -0
- pycityagent/environment/utils/base64.py +16 -0
- pycityagent/environment/utils/const.py +242 -0
- pycityagent/environment/utils/geojson.py +26 -0
- pycityagent/environment/utils/grpc.py +57 -0
- pycityagent/environment/utils/map_utils.py +157 -0
- pycityagent/environment/utils/port.py +11 -0
- pycityagent/environment/utils/protobuf.py +39 -0
- pycityagent/llm/__init__.py +6 -0
- pycityagent/llm/embedding.py +136 -0
- pycityagent/llm/llm.py +430 -0
- pycityagent/llm/llmconfig.py +15 -0
- pycityagent/llm/utils.py +6 -0
- pycityagent/memory/__init__.py +11 -0
- pycityagent/memory/const.py +41 -0
- pycityagent/memory/memory.py +453 -0
- pycityagent/memory/memory_base.py +168 -0
- pycityagent/memory/profile.py +165 -0
- pycityagent/memory/self_define.py +165 -0
- pycityagent/memory/state.py +173 -0
- pycityagent/memory/utils.py +27 -0
- pycityagent/message/__init__.py +0 -0
- pycityagent/simulation/__init__.py +7 -0
- pycityagent/simulation/interview.py +36 -0
- pycityagent/simulation/simulation.py +352 -0
- pycityagent/simulation/survey/__init__.py +9 -0
- pycityagent/simulation/survey/manager.py +67 -0
- pycityagent/simulation/survey/models.py +49 -0
- pycityagent/simulation/ui/__init__.py +3 -0
- pycityagent/simulation/ui/interface.py +602 -0
- pycityagent/utils/__init__.py +0 -0
- pycityagent/utils/decorators.py +89 -0
- pycityagent/utils/parsers/__init__.py +12 -0
- pycityagent/utils/parsers/code_block_parser.py +37 -0
- pycityagent/utils/parsers/json_parser.py +86 -0
- pycityagent/utils/parsers/parser_base.py +60 -0
- pycityagent/workflow/__init__.py +24 -0
- pycityagent/workflow/block.py +164 -0
- pycityagent/workflow/prompt.py +72 -0
- pycityagent/workflow/tool.py +246 -0
- pycityagent/workflow/trigger.py +150 -0
- pycityagent-2.0.0a2.dist-info/METADATA +208 -0
- pycityagent-2.0.0a2.dist-info/RECORD +69 -0
- {pycityagent-1.0.0.dist-info → pycityagent-2.0.0a2.dist-info}/WHEEL +1 -2
- pycityagent/ac/__init__.py +0 -6
- pycityagent/ac/ac.py +0 -50
- pycityagent/ac/action.py +0 -14
- pycityagent/ac/controled.py +0 -13
- pycityagent/ac/converse.py +0 -31
- pycityagent/ac/idle.py +0 -17
- pycityagent/ac/shop.py +0 -80
- pycityagent/ac/trip.py +0 -37
- pycityagent/brain/__init__.py +0 -10
- pycityagent/brain/brain.py +0 -52
- pycityagent/brain/brainfc.py +0 -10
- pycityagent/brain/memory.py +0 -541
- pycityagent/brain/persistence/social.py +0 -1
- pycityagent/brain/persistence/spatial.py +0 -14
- pycityagent/brain/reason/shop.py +0 -37
- pycityagent/brain/reason/social.py +0 -148
- pycityagent/brain/reason/trip.py +0 -67
- pycityagent/brain/reason/user.py +0 -122
- pycityagent/brain/retrive/social.py +0 -6
- pycityagent/brain/scheduler.py +0 -408
- pycityagent/brain/sence.py +0 -375
- pycityagent/cc/__init__.py +0 -5
- pycityagent/cc/cc.py +0 -102
- pycityagent/cc/conve.py +0 -6
- pycityagent/cc/idle.py +0 -20
- pycityagent/cc/shop.py +0 -6
- pycityagent/cc/trip.py +0 -13
- pycityagent/cc/user.py +0 -13
- pycityagent/hubconnector/__init__.py +0 -3
- pycityagent/hubconnector/hubconnector.py +0 -137
- pycityagent/image/__init__.py +0 -3
- pycityagent/image/image.py +0 -158
- pycityagent/simulator.py +0 -161
- pycityagent/st/__init__.py +0 -4
- pycityagent/st/st.py +0 -96
- pycityagent/urbanllm/__init__.py +0 -3
- pycityagent/urbanllm/urbanllm.py +0 -132
- pycityagent-1.0.0.dist-info/LICENSE +0 -21
- pycityagent-1.0.0.dist-info/METADATA +0 -181
- pycityagent-1.0.0.dist-info/RECORD +0 -48
- pycityagent-1.0.0.dist-info/top_level.txt +0 -1
- /pycityagent/{brain/persistence/__init__.py → config.py} +0 -0
- /pycityagent/{brain/reason → environment/interact}/__init__.py +0 -0
- /pycityagent/{brain/retrive → environment/message}/__init__.py +0 -0
@@ -0,0 +1,165 @@
|
|
1
|
+
"""
|
2
|
+
Agent Profile
|
3
|
+
"""
|
4
|
+
|
5
|
+
from copy import deepcopy
|
6
|
+
from typing import (Any, Callable, Dict, List, Optional, Sequence, Tuple,
|
7
|
+
Union, cast)
|
8
|
+
|
9
|
+
from ..utils.decorators import lock_decorator
|
10
|
+
from .const import *
|
11
|
+
from .memory_base import MemoryBase, MemoryUnit
|
12
|
+
from .utils import convert_msg_to_sequence
|
13
|
+
|
14
|
+
|
15
|
+
class ProfileMemoryUnit(MemoryUnit):
|
16
|
+
def __init__(
|
17
|
+
self,
|
18
|
+
content: Optional[Dict] = None,
|
19
|
+
activate_timestamp: bool = False,
|
20
|
+
) -> None:
|
21
|
+
super().__init__(
|
22
|
+
content=content,
|
23
|
+
required_attributes=PROFILE_ATTRIBUTES,
|
24
|
+
activate_timestamp=activate_timestamp,
|
25
|
+
)
|
26
|
+
|
27
|
+
|
28
|
+
class ProfileMemory(MemoryBase):
|
29
|
+
def __init__(
|
30
|
+
self,
|
31
|
+
msg: Optional[
|
32
|
+
Union[ProfileMemoryUnit, Sequence[ProfileMemoryUnit], Dict, Sequence[Dict]]
|
33
|
+
] = None,
|
34
|
+
activate_timestamp: bool = False,
|
35
|
+
) -> None:
|
36
|
+
super().__init__()
|
37
|
+
if msg is None:
|
38
|
+
msg = deepcopy(PROFILE_ATTRIBUTES)
|
39
|
+
self.activate_timestamp = activate_timestamp
|
40
|
+
msg = convert_msg_to_sequence(
|
41
|
+
msg,
|
42
|
+
sequence_type=ProfileMemoryUnit,
|
43
|
+
activate_timestamp=self.activate_timestamp,
|
44
|
+
)
|
45
|
+
for unit in msg:
|
46
|
+
self._memories[unit] = {}
|
47
|
+
|
48
|
+
@lock_decorator
|
49
|
+
async def add(
|
50
|
+
self, msg: Union[ProfileMemoryUnit, Sequence[ProfileMemoryUnit]]
|
51
|
+
) -> None:
|
52
|
+
_memories = self._memories
|
53
|
+
msg = convert_msg_to_sequence(
|
54
|
+
msg,
|
55
|
+
sequence_type=ProfileMemoryUnit,
|
56
|
+
activate_timestamp=self.activate_timestamp,
|
57
|
+
)
|
58
|
+
for unit in msg:
|
59
|
+
if unit not in _memories:
|
60
|
+
_memories[unit] = {}
|
61
|
+
|
62
|
+
@lock_decorator
|
63
|
+
async def pop(self, index: int) -> ProfileMemoryUnit:
|
64
|
+
|
65
|
+
_memories = self._memories
|
66
|
+
try:
|
67
|
+
pop_unit = list(_memories.keys())[index]
|
68
|
+
_memories.pop(pop_unit)
|
69
|
+
|
70
|
+
return pop_unit
|
71
|
+
except IndexError as e:
|
72
|
+
|
73
|
+
raise ValueError(f"Index {index} not in memory!")
|
74
|
+
|
75
|
+
@lock_decorator
|
76
|
+
async def load(
|
77
|
+
self,
|
78
|
+
snapshots: Union[Dict, Sequence[Dict]],
|
79
|
+
reset_memory: bool = False,
|
80
|
+
) -> None:
|
81
|
+
if reset_memory:
|
82
|
+
self._memories = {}
|
83
|
+
msg = convert_msg_to_sequence(
|
84
|
+
snapshots,
|
85
|
+
sequence_type=ProfileMemoryUnit,
|
86
|
+
activate_timestamp=self.activate_timestamp,
|
87
|
+
)
|
88
|
+
for unit in msg:
|
89
|
+
if unit not in self._memories:
|
90
|
+
self._memories[unit] = {}
|
91
|
+
|
92
|
+
@lock_decorator
|
93
|
+
async def export(
|
94
|
+
self,
|
95
|
+
) -> Sequence[Dict]:
|
96
|
+
_res = []
|
97
|
+
for m in self._memories.keys():
|
98
|
+
m = cast(ProfileMemoryUnit, m)
|
99
|
+
_dict_values = await m.dict_values()
|
100
|
+
_res.append(_dict_values)
|
101
|
+
|
102
|
+
return _res
|
103
|
+
|
104
|
+
async def reset(self) -> None:
|
105
|
+
self._memories = {}
|
106
|
+
|
107
|
+
# interact
|
108
|
+
@lock_decorator
|
109
|
+
async def get(self, key: Any):
|
110
|
+
_latest_memories = self._fetch_recent_memory()
|
111
|
+
_latest_memory: ProfileMemoryUnit = _latest_memories[-1]
|
112
|
+
return _latest_memory[key]
|
113
|
+
|
114
|
+
@lock_decorator
|
115
|
+
async def get_top_k(
|
116
|
+
self,
|
117
|
+
key: Any,
|
118
|
+
metric: Callable[[Any], Any],
|
119
|
+
top_k: Optional[int] = None,
|
120
|
+
preserve_order: bool = True,
|
121
|
+
) -> Union[Sequence[Any], Any]:
|
122
|
+
_latest_memories = self._fetch_recent_memory()
|
123
|
+
_latest_memory: ProfileMemoryUnit = _latest_memories[-1]
|
124
|
+
_top_k = await _latest_memory.top_k_values(key, metric, top_k, preserve_order)
|
125
|
+
|
126
|
+
return _top_k
|
127
|
+
|
128
|
+
@lock_decorator
|
129
|
+
async def update(self, key: Any, value: Any, store_snapshot: bool = False):
|
130
|
+
_latest_memories = self._fetch_recent_memory()
|
131
|
+
_latest_memory: ProfileMemoryUnit = _latest_memories[-1]
|
132
|
+
if not store_snapshot:
|
133
|
+
# write in place
|
134
|
+
await _latest_memory.update({key: value})
|
135
|
+
|
136
|
+
else:
|
137
|
+
# insert new unit
|
138
|
+
_dict_values = await _latest_memory.dict_values()
|
139
|
+
_content = deepcopy(
|
140
|
+
{k: v for k, v in _dict_values.items() if k not in {TIME_STAMP_KEY}}
|
141
|
+
)
|
142
|
+
_content.update({key: value})
|
143
|
+
msg = ProfileMemoryUnit(_content, self.activate_timestamp)
|
144
|
+
for unit in [msg]:
|
145
|
+
if unit not in self._memories:
|
146
|
+
self._memories[unit] = {}
|
147
|
+
|
148
|
+
@lock_decorator
|
149
|
+
async def update_dict(self, to_update_dict: Dict, store_snapshot: bool = False):
|
150
|
+
_latest_memories = self._fetch_recent_memory()
|
151
|
+
_latest_memory: ProfileMemoryUnit = _latest_memories[-1]
|
152
|
+
if not store_snapshot:
|
153
|
+
# write in place
|
154
|
+
await _latest_memory.update(to_update_dict)
|
155
|
+
else:
|
156
|
+
# insert new unit
|
157
|
+
_dict_values = await _latest_memory.dict_values()
|
158
|
+
_content = deepcopy(
|
159
|
+
{k: v for k, v in _dict_values.items() if k not in {TIME_STAMP_KEY}}
|
160
|
+
)
|
161
|
+
_content.update(to_update_dict)
|
162
|
+
msg = ProfileMemoryUnit(_content, self.activate_timestamp)
|
163
|
+
for unit in [msg]:
|
164
|
+
if unit not in self._memories:
|
165
|
+
self._memories[unit] = {}
|
@@ -0,0 +1,165 @@
|
|
1
|
+
"""
|
2
|
+
Self Define Data
|
3
|
+
"""
|
4
|
+
|
5
|
+
from copy import deepcopy
|
6
|
+
from typing import (Any, Callable, Dict, List, Optional, Sequence, Tuple,
|
7
|
+
Union, cast)
|
8
|
+
|
9
|
+
from ..utils.decorators import lock_decorator
|
10
|
+
from .const import *
|
11
|
+
from .memory_base import MemoryBase, MemoryUnit
|
12
|
+
from .utils import convert_msg_to_sequence
|
13
|
+
|
14
|
+
|
15
|
+
class DynamicMemoryUnit(MemoryUnit):
|
16
|
+
def __init__(
|
17
|
+
self,
|
18
|
+
content: Optional[Dict] = None,
|
19
|
+
required_attributes: Optional[Dict] = None,
|
20
|
+
activate_timestamp: bool = False,
|
21
|
+
) -> None:
|
22
|
+
super().__init__(
|
23
|
+
content=content,
|
24
|
+
required_attributes=required_attributes,
|
25
|
+
activate_timestamp=activate_timestamp,
|
26
|
+
)
|
27
|
+
|
28
|
+
|
29
|
+
class DynamicMemory(MemoryBase):
|
30
|
+
|
31
|
+
def __init__(
|
32
|
+
self,
|
33
|
+
required_attributes: Dict[Any, Any],
|
34
|
+
activate_timestamp: bool = False,
|
35
|
+
) -> None:
|
36
|
+
super().__init__()
|
37
|
+
self._required_attributes = deepcopy(required_attributes)
|
38
|
+
self.activate_timestamp = activate_timestamp
|
39
|
+
msg = DynamicMemoryUnit(
|
40
|
+
self._required_attributes, None, self.activate_timestamp
|
41
|
+
)
|
42
|
+
self._memories[msg] = {}
|
43
|
+
|
44
|
+
@lock_decorator
|
45
|
+
async def add(
|
46
|
+
self, msg: Union[DynamicMemoryUnit, Sequence[DynamicMemoryUnit]]
|
47
|
+
) -> None:
|
48
|
+
_memories = self._memories
|
49
|
+
msg = convert_msg_to_sequence(
|
50
|
+
msg,
|
51
|
+
sequence_type=DynamicMemoryUnit,
|
52
|
+
activate_timestamp=self.activate_timestamp,
|
53
|
+
)
|
54
|
+
for unit in msg:
|
55
|
+
if unit not in _memories:
|
56
|
+
_memories[unit] = {}
|
57
|
+
|
58
|
+
@lock_decorator
|
59
|
+
async def pop(self, index: int) -> DynamicMemoryUnit:
|
60
|
+
_memories = self._memories
|
61
|
+
try:
|
62
|
+
pop_unit = list(_memories.keys())[index]
|
63
|
+
_memories.pop(pop_unit)
|
64
|
+
|
65
|
+
return pop_unit
|
66
|
+
except IndexError as e:
|
67
|
+
|
68
|
+
raise ValueError(f"Index {index} not in memory!")
|
69
|
+
|
70
|
+
@lock_decorator
|
71
|
+
async def load(
|
72
|
+
self,
|
73
|
+
snapshots: Union[Dict, Sequence[Dict]],
|
74
|
+
reset_memory: bool = False,
|
75
|
+
) -> None:
|
76
|
+
if reset_memory:
|
77
|
+
self._memories = {}
|
78
|
+
msg = convert_msg_to_sequence(
|
79
|
+
snapshots,
|
80
|
+
sequence_type=DynamicMemoryUnit,
|
81
|
+
activate_timestamp=self.activate_timestamp,
|
82
|
+
)
|
83
|
+
for unit in msg:
|
84
|
+
if unit not in self._memories:
|
85
|
+
self._memories[unit] = {}
|
86
|
+
|
87
|
+
@lock_decorator
|
88
|
+
async def export(
|
89
|
+
self,
|
90
|
+
) -> Sequence[Dict]:
|
91
|
+
_res = []
|
92
|
+
for m in self._memories.keys():
|
93
|
+
m = cast(DynamicMemoryUnit, m)
|
94
|
+
_dict_values = await m.dict_values()
|
95
|
+
_res.append(_dict_values)
|
96
|
+
|
97
|
+
return _res
|
98
|
+
|
99
|
+
async def reset(self) -> None:
|
100
|
+
self._memories = {}
|
101
|
+
|
102
|
+
# interact
|
103
|
+
@lock_decorator
|
104
|
+
async def get(self, key: Any):
|
105
|
+
_latest_memories = self._fetch_recent_memory()
|
106
|
+
_latest_memory: DynamicMemoryUnit = _latest_memories[-1]
|
107
|
+
|
108
|
+
return _latest_memory[key]
|
109
|
+
|
110
|
+
@lock_decorator
|
111
|
+
async def get_top_k(
|
112
|
+
self,
|
113
|
+
key: Any,
|
114
|
+
metric: Callable[[Any], Any],
|
115
|
+
top_k: Optional[int] = None,
|
116
|
+
preserve_order: bool = True,
|
117
|
+
) -> Union[Sequence[Any], Any]:
|
118
|
+
_latest_memories = self._fetch_recent_memory()
|
119
|
+
_latest_memory: DynamicMemoryUnit = _latest_memories[-1]
|
120
|
+
_top_k = await _latest_memory.top_k_values(key, metric, top_k, preserve_order)
|
121
|
+
|
122
|
+
return _top_k
|
123
|
+
|
124
|
+
@lock_decorator
|
125
|
+
async def update(self, key: Any, value: Any, store_snapshot: bool = False):
|
126
|
+
_latest_memories = self._fetch_recent_memory()
|
127
|
+
_latest_memory: DynamicMemoryUnit = _latest_memories[-1]
|
128
|
+
if not store_snapshot:
|
129
|
+
# write in place
|
130
|
+
await _latest_memory.update({key: value})
|
131
|
+
|
132
|
+
else:
|
133
|
+
# insert new unit
|
134
|
+
_dict_values = await _latest_memory.dict_values()
|
135
|
+
_content = deepcopy(
|
136
|
+
{k: v for k, v in _dict_values.items() if k not in {TIME_STAMP_KEY}}
|
137
|
+
)
|
138
|
+
_content.update({key: value})
|
139
|
+
msg = DynamicMemoryUnit(
|
140
|
+
_content, self._required_attributes, self.activate_timestamp
|
141
|
+
)
|
142
|
+
for unit in [msg]:
|
143
|
+
if unit not in self._memories:
|
144
|
+
self._memories[unit] = {}
|
145
|
+
|
146
|
+
@lock_decorator
|
147
|
+
async def update_dict(self, to_update_dict: Dict, store_snapshot: bool = False):
|
148
|
+
_latest_memories = self._fetch_recent_memory()
|
149
|
+
_latest_memory: DynamicMemoryUnit = _latest_memories[-1]
|
150
|
+
if not store_snapshot:
|
151
|
+
# write in place
|
152
|
+
await _latest_memory.update(to_update_dict)
|
153
|
+
else:
|
154
|
+
# insert new unit
|
155
|
+
_dict_values = await _latest_memory.dict_values()
|
156
|
+
_content = deepcopy(
|
157
|
+
{k: v for k, v in _dict_values.items() if k not in {TIME_STAMP_KEY}}
|
158
|
+
)
|
159
|
+
_content.update(to_update_dict)
|
160
|
+
msg = DynamicMemoryUnit(
|
161
|
+
_content, self._required_attributes, self.activate_timestamp
|
162
|
+
)
|
163
|
+
for unit in [msg]:
|
164
|
+
if unit not in self._memories:
|
165
|
+
self._memories[unit] = {}
|
@@ -0,0 +1,173 @@
|
|
1
|
+
"""
|
2
|
+
Agent State
|
3
|
+
"""
|
4
|
+
|
5
|
+
from copy import deepcopy
|
6
|
+
from typing import (Any, Callable, Dict, List, Optional, Sequence, Tuple,
|
7
|
+
Union, cast)
|
8
|
+
|
9
|
+
from ..utils.decorators import lock_decorator
|
10
|
+
from .const import *
|
11
|
+
from .memory_base import MemoryBase, MemoryUnit
|
12
|
+
from .utils import convert_msg_to_sequence
|
13
|
+
|
14
|
+
|
15
|
+
class StateMemoryUnit(MemoryUnit):
|
16
|
+
def __init__(
|
17
|
+
self,
|
18
|
+
content: Optional[Dict] = None,
|
19
|
+
activate_timestamp: bool = False,
|
20
|
+
) -> None:
|
21
|
+
super().__init__(
|
22
|
+
content=content,
|
23
|
+
required_attributes=STATE_ATTRIBUTES,
|
24
|
+
activate_timestamp=activate_timestamp,
|
25
|
+
)
|
26
|
+
|
27
|
+
|
28
|
+
class StateMemory(MemoryBase):
|
29
|
+
def __init__(
|
30
|
+
self,
|
31
|
+
msg: Optional[
|
32
|
+
Union[MemoryUnit, Sequence[MemoryUnit], Dict, Sequence[Dict]]
|
33
|
+
] = None,
|
34
|
+
activate_timestamp: bool = False,
|
35
|
+
) -> None:
|
36
|
+
super().__init__()
|
37
|
+
if msg is None:
|
38
|
+
msg = deepcopy(STATE_ATTRIBUTES)
|
39
|
+
self.activate_timestamp = activate_timestamp
|
40
|
+
msg = convert_msg_to_sequence(
|
41
|
+
msg,
|
42
|
+
sequence_type=StateMemoryUnit,
|
43
|
+
activate_timestamp=self.activate_timestamp,
|
44
|
+
)
|
45
|
+
for unit in msg:
|
46
|
+
self._memories[unit] = {}
|
47
|
+
|
48
|
+
@lock_decorator
|
49
|
+
async def add(self, msg: Union[MemoryUnit, Sequence[MemoryUnit]]) -> None:
|
50
|
+
|
51
|
+
_memories = self._memories
|
52
|
+
msg = convert_msg_to_sequence(
|
53
|
+
msg,
|
54
|
+
sequence_type=StateMemoryUnit,
|
55
|
+
activate_timestamp=self.activate_timestamp,
|
56
|
+
)
|
57
|
+
for unit in msg:
|
58
|
+
if unit not in _memories:
|
59
|
+
_memories[unit] = {}
|
60
|
+
|
61
|
+
@lock_decorator
|
62
|
+
async def pop(self, index: int) -> MemoryUnit:
|
63
|
+
|
64
|
+
_memories = self._memories
|
65
|
+
try:
|
66
|
+
pop_unit = list(_memories.keys())[index]
|
67
|
+
_memories.pop(pop_unit)
|
68
|
+
|
69
|
+
return pop_unit
|
70
|
+
except IndexError as e:
|
71
|
+
|
72
|
+
raise ValueError(f"Index {index} not in memory!")
|
73
|
+
|
74
|
+
@lock_decorator
|
75
|
+
async def load(
|
76
|
+
self,
|
77
|
+
snapshots: Union[Dict, Sequence[Dict]],
|
78
|
+
reset_memory: bool = False,
|
79
|
+
) -> None:
|
80
|
+
|
81
|
+
if reset_memory:
|
82
|
+
self._memories = {}
|
83
|
+
msg = convert_msg_to_sequence(
|
84
|
+
snapshots,
|
85
|
+
sequence_type=StateMemoryUnit,
|
86
|
+
activate_timestamp=self.activate_timestamp,
|
87
|
+
)
|
88
|
+
for unit in msg:
|
89
|
+
if unit not in self._memories:
|
90
|
+
self._memories[unit] = {}
|
91
|
+
|
92
|
+
@lock_decorator
|
93
|
+
async def export(
|
94
|
+
self,
|
95
|
+
) -> Sequence[Dict]:
|
96
|
+
|
97
|
+
_res = []
|
98
|
+
for m in self._memories.keys():
|
99
|
+
m = cast(StateMemoryUnit, m)
|
100
|
+
_dict_values = await m.dict_values()
|
101
|
+
_res.append(_dict_values)
|
102
|
+
|
103
|
+
return _res
|
104
|
+
|
105
|
+
async def reset(self) -> None:
|
106
|
+
|
107
|
+
self._memories = {}
|
108
|
+
|
109
|
+
# interact
|
110
|
+
@lock_decorator
|
111
|
+
async def get(self, key: Any):
|
112
|
+
|
113
|
+
_latest_memories = self._fetch_recent_memory()
|
114
|
+
_latest_memory: StateMemoryUnit = _latest_memories[-1]
|
115
|
+
|
116
|
+
return _latest_memory[key]
|
117
|
+
|
118
|
+
@lock_decorator
|
119
|
+
async def get_top_k(
|
120
|
+
self,
|
121
|
+
key: Any,
|
122
|
+
metric: Callable[[Any], Any],
|
123
|
+
top_k: Optional[int] = None,
|
124
|
+
preserve_order: bool = True,
|
125
|
+
) -> Union[Sequence[Any], Any]:
|
126
|
+
|
127
|
+
_latest_memories = self._fetch_recent_memory()
|
128
|
+
_latest_memory: StateMemoryUnit = _latest_memories[-1]
|
129
|
+
_top_k = await _latest_memory.top_k_values(key, metric, top_k, preserve_order)
|
130
|
+
|
131
|
+
return _top_k
|
132
|
+
|
133
|
+
@lock_decorator
|
134
|
+
async def update(self, key: Any, value: Any, store_snapshot: bool = False):
|
135
|
+
|
136
|
+
_latest_memories = self._fetch_recent_memory()
|
137
|
+
_latest_memory: StateMemoryUnit = _latest_memories[-1]
|
138
|
+
if not store_snapshot:
|
139
|
+
# write in place
|
140
|
+
await _latest_memory.update({key: value})
|
141
|
+
|
142
|
+
else:
|
143
|
+
# insert new unit
|
144
|
+
_dict_values = await _latest_memory.dict_values()
|
145
|
+
_content = deepcopy(
|
146
|
+
{k: v for k, v in _dict_values.items() if k not in {TIME_STAMP_KEY}}
|
147
|
+
)
|
148
|
+
_content.update({key: value})
|
149
|
+
msg = StateMemoryUnit(_content, self.activate_timestamp)
|
150
|
+
for unit in [msg]:
|
151
|
+
if unit not in self._memories:
|
152
|
+
self._memories[unit] = {}
|
153
|
+
|
154
|
+
@lock_decorator
|
155
|
+
async def update_dict(self, to_update_dict: Dict, store_snapshot: bool = False):
|
156
|
+
|
157
|
+
_latest_memories = self._fetch_recent_memory()
|
158
|
+
_latest_memory: StateMemoryUnit = _latest_memories[-1]
|
159
|
+
if not store_snapshot:
|
160
|
+
# write in place
|
161
|
+
await _latest_memory.update(to_update_dict)
|
162
|
+
|
163
|
+
else:
|
164
|
+
# insert new unit
|
165
|
+
_dict_values = await _latest_memory.dict_values()
|
166
|
+
_content = deepcopy(
|
167
|
+
{k: v for k, v in _dict_values.items() if k not in {TIME_STAMP_KEY}}
|
168
|
+
)
|
169
|
+
_content.update(to_update_dict)
|
170
|
+
msg = StateMemoryUnit(_content, self.activate_timestamp)
|
171
|
+
for unit in [msg]:
|
172
|
+
if unit not in self._memories:
|
173
|
+
self._memories[unit] = {}
|
@@ -0,0 +1,27 @@
|
|
1
|
+
from typing import Any, Dict, List, Optional, Sequence, Tuple, Union
|
2
|
+
|
3
|
+
from .memory_base import MemoryUnit
|
4
|
+
|
5
|
+
|
6
|
+
def convert_msg_to_sequence(
|
7
|
+
msg: Union[Any, Sequence[Any]],
|
8
|
+
sequence_type=MemoryUnit,
|
9
|
+
activate_timestamp: bool = False,
|
10
|
+
) -> Sequence[Any]:
|
11
|
+
# Convert the input message to a sequence if it is not already one
|
12
|
+
if not isinstance(msg, Sequence):
|
13
|
+
_sequence_msg = [msg]
|
14
|
+
else:
|
15
|
+
_sequence_msg = msg
|
16
|
+
|
17
|
+
# Initialize an empty list to store the converted MemoryUnit objects
|
18
|
+
_sequence_unit = []
|
19
|
+
|
20
|
+
# Iterate over each unit in the sequence
|
21
|
+
for unit in _sequence_msg:
|
22
|
+
# If the unit is not already a MemoryUnit, convert it to one
|
23
|
+
if not isinstance(unit, sequence_type):
|
24
|
+
unit = sequence_type(content=unit, activate_timestamp=activate_timestamp)
|
25
|
+
_sequence_unit.append(unit)
|
26
|
+
|
27
|
+
return _sequence_unit
|
File without changes
|
@@ -0,0 +1,36 @@
|
|
1
|
+
from dataclasses import dataclass
|
2
|
+
from datetime import datetime
|
3
|
+
from typing import List, Optional
|
4
|
+
|
5
|
+
@dataclass
|
6
|
+
class InterviewRecord:
|
7
|
+
"""采访记录"""
|
8
|
+
timestamp: datetime
|
9
|
+
agent_name: str
|
10
|
+
question: str
|
11
|
+
response: str
|
12
|
+
blocking: bool
|
13
|
+
|
14
|
+
class InterviewManager:
|
15
|
+
"""采访管理器"""
|
16
|
+
def __init__(self):
|
17
|
+
self._history: List[InterviewRecord] = []
|
18
|
+
|
19
|
+
def add_record(self, agent_name: str, question: str, response: str, blocking: bool):
|
20
|
+
"""添加采访记录"""
|
21
|
+
record = InterviewRecord(
|
22
|
+
timestamp=datetime.now(),
|
23
|
+
agent_name=agent_name,
|
24
|
+
question=question,
|
25
|
+
response=response,
|
26
|
+
blocking=blocking
|
27
|
+
)
|
28
|
+
self._history.append(record)
|
29
|
+
|
30
|
+
def get_agent_history(self, agent_name: str) -> List[InterviewRecord]:
|
31
|
+
"""获取指定智能体的采访历史"""
|
32
|
+
return [r for r in self._history if r.agent_name == agent_name]
|
33
|
+
|
34
|
+
def get_recent_history(self, limit: int = 10) -> List[InterviewRecord]:
|
35
|
+
"""获取最近的采访记录"""
|
36
|
+
return sorted(self._history, key=lambda x: x.timestamp, reverse=True)[:limit]
|