pycityagent 2.0.0a52__cp311-cp311-macosx_11_0_arm64.whl → 2.0.0a54__cp311-cp311-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 +83 -62
- pycityagent/agent/agent_base.py +81 -54
- pycityagent/cityagent/bankagent.py +5 -7
- pycityagent/cityagent/blocks/__init__.py +0 -2
- pycityagent/cityagent/blocks/cognition_block.py +149 -172
- pycityagent/cityagent/blocks/economy_block.py +90 -129
- pycityagent/cityagent/blocks/mobility_block.py +56 -29
- pycityagent/cityagent/blocks/needs_block.py +163 -145
- pycityagent/cityagent/blocks/other_block.py +17 -9
- pycityagent/cityagent/blocks/plan_block.py +45 -57
- pycityagent/cityagent/blocks/social_block.py +70 -51
- pycityagent/cityagent/blocks/utils.py +2 -0
- pycityagent/cityagent/firmagent.py +6 -7
- pycityagent/cityagent/governmentagent.py +7 -9
- pycityagent/cityagent/memory_config.py +48 -48
- pycityagent/cityagent/message_intercept.py +99 -0
- pycityagent/cityagent/nbsagent.py +6 -29
- pycityagent/cityagent/societyagent.py +325 -127
- pycityagent/cli/wrapper.py +4 -0
- pycityagent/economy/econ_client.py +0 -2
- pycityagent/environment/__init__.py +7 -1
- pycityagent/environment/sim/client.py +10 -1
- pycityagent/environment/sim/clock_service.py +2 -2
- pycityagent/environment/sim/pause_service.py +61 -0
- pycityagent/environment/sim/sim_env.py +34 -46
- pycityagent/environment/simulator.py +18 -14
- pycityagent/llm/embeddings.py +0 -24
- pycityagent/llm/llm.py +18 -10
- pycityagent/memory/faiss_query.py +29 -26
- pycityagent/memory/memory.py +733 -247
- pycityagent/message/__init__.py +8 -1
- pycityagent/message/message_interceptor.py +322 -0
- pycityagent/message/messager.py +42 -11
- pycityagent/pycityagent-sim +0 -0
- pycityagent/simulation/agentgroup.py +137 -96
- pycityagent/simulation/simulation.py +184 -38
- pycityagent/simulation/storage/pg.py +2 -2
- pycityagent/tools/tool.py +7 -9
- pycityagent/utils/__init__.py +7 -2
- pycityagent/utils/pg_query.py +1 -0
- pycityagent/utils/survey_util.py +26 -23
- pycityagent/workflow/block.py +14 -7
- {pycityagent-2.0.0a52.dist-info → pycityagent-2.0.0a54.dist-info}/METADATA +2 -2
- {pycityagent-2.0.0a52.dist-info → pycityagent-2.0.0a54.dist-info}/RECORD +48 -46
- pycityagent/cityagent/blocks/time_block.py +0 -116
- {pycityagent-2.0.0a52.dist-info → pycityagent-2.0.0a54.dist-info}/LICENSE +0 -0
- {pycityagent-2.0.0a52.dist-info → pycityagent-2.0.0a54.dist-info}/WHEEL +0 -0
- {pycityagent-2.0.0a52.dist-info → pycityagent-2.0.0a54.dist-info}/entry_points.txt +0 -0
- {pycityagent-2.0.0a52.dist-info → pycityagent-2.0.0a54.dist-info}/top_level.txt +0 -0
pycityagent/agent/agent.py
CHANGED
@@ -13,7 +13,7 @@ from ..economy import EconomyClient
|
|
13
13
|
from ..environment import Simulator
|
14
14
|
from ..llm import LLM
|
15
15
|
from ..memory import Memory
|
16
|
-
from ..message
|
16
|
+
from ..message import MessageInterceptor, Messager
|
17
17
|
from ..metrics import MlflowClient
|
18
18
|
from .agent_base import Agent, AgentType
|
19
19
|
|
@@ -30,10 +30,10 @@ class CitizenAgent(Agent):
|
|
30
30
|
name: str,
|
31
31
|
llm_client: Optional[LLM] = None,
|
32
32
|
simulator: Optional[Simulator] = None,
|
33
|
-
mlflow_client: Optional[MlflowClient] = None,
|
34
33
|
memory: Optional[Memory] = None,
|
35
34
|
economy_client: Optional[EconomyClient] = None,
|
36
35
|
messager: Optional[Messager] = None, # type:ignore
|
36
|
+
message_interceptor: Optional[MessageInterceptor] = None, # type:ignore
|
37
37
|
avro_file: Optional[dict] = None,
|
38
38
|
) -> None:
|
39
39
|
super().__init__(
|
@@ -42,11 +42,12 @@ class CitizenAgent(Agent):
|
|
42
42
|
llm_client=llm_client,
|
43
43
|
economy_client=economy_client,
|
44
44
|
messager=messager,
|
45
|
+
message_interceptor=message_interceptor,
|
45
46
|
simulator=simulator,
|
46
|
-
mlflow_client=mlflow_client,
|
47
47
|
memory=memory,
|
48
48
|
avro_file=avro_file,
|
49
49
|
)
|
50
|
+
self._mlflow_client = None
|
50
51
|
|
51
52
|
async def bind_to_simulator(self):
|
52
53
|
await self._bind_to_simulator()
|
@@ -62,42 +63,31 @@ class CitizenAgent(Agent):
|
|
62
63
|
if self._simulator is None:
|
63
64
|
logger.warning("Simulator is not set")
|
64
65
|
return
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
continue
|
91
|
-
resp = await simulator.add_person(
|
92
|
-
dict2pb(dict_person, person_pb2.Person())
|
93
|
-
)
|
94
|
-
person_id = resp["person_id"]
|
95
|
-
await memory.update("id", person_id, protect_llm_read_only_fields=False)
|
96
|
-
logger.debug(f"Binding to Person `{person_id}` just added to Simulator")
|
97
|
-
# 防止模拟器还没有到prepare阶段导致get_person出错
|
98
|
-
self._has_bound_to_simulator = True
|
99
|
-
self._agent_id = person_id
|
100
|
-
self.memory.set_agent_id(person_id)
|
66
|
+
FROM_MEMORY_KEYS = {
|
67
|
+
"attribute",
|
68
|
+
"home",
|
69
|
+
"work",
|
70
|
+
"vehicle_attribute",
|
71
|
+
"bus_attribute",
|
72
|
+
"pedestrian_attribute",
|
73
|
+
"bike_attribute",
|
74
|
+
}
|
75
|
+
simulator = self.simulator
|
76
|
+
status = self.status
|
77
|
+
dict_person = deepcopy(self._person_template)
|
78
|
+
for _key in FROM_MEMORY_KEYS:
|
79
|
+
try:
|
80
|
+
_value = await status.get(_key)
|
81
|
+
if _value:
|
82
|
+
dict_person[_key] = _value
|
83
|
+
except KeyError as e:
|
84
|
+
continue
|
85
|
+
resp = await simulator.add_person(dict2pb(dict_person, person_pb2.Person()))
|
86
|
+
person_id = resp["person_id"]
|
87
|
+
await status.update("id", person_id, protect_llm_read_only_fields=False)
|
88
|
+
logger.debug(f"Binding to Person `{person_id}` just added to Simulator")
|
89
|
+
self._agent_id = person_id
|
90
|
+
self.status.set_agent_id(person_id)
|
101
91
|
|
102
92
|
async def _bind_to_economy(self):
|
103
93
|
if self._economy_client is None:
|
@@ -109,8 +99,8 @@ class CitizenAgent(Agent):
|
|
109
99
|
await self._economy_client.remove_agents([self._agent_id])
|
110
100
|
except:
|
111
101
|
pass
|
112
|
-
person_id = await self.
|
113
|
-
currency = await self.
|
102
|
+
person_id = await self.status.get("id")
|
103
|
+
currency = await self.status.get("currency")
|
114
104
|
await self._economy_client.add_agents(
|
115
105
|
{
|
116
106
|
"id": person_id,
|
@@ -128,17 +118,32 @@ class CitizenAgent(Agent):
|
|
128
118
|
# 从消息中解析发送者 ID 和消息内容
|
129
119
|
target = payload["target"]
|
130
120
|
sender_id = payload["from"]
|
131
|
-
content = await self.
|
121
|
+
content = await self.status.get(f"{target}")
|
132
122
|
payload = {
|
133
123
|
"from": self._uuid,
|
134
124
|
"content": content,
|
135
125
|
}
|
136
126
|
await self._send_message(sender_id, payload, "gather")
|
137
127
|
|
128
|
+
@property
|
129
|
+
def mlflow_client(self) -> MlflowClient:
|
130
|
+
"""The Agent's MlflowClient"""
|
131
|
+
if self._mlflow_client is None:
|
132
|
+
raise RuntimeError(
|
133
|
+
f"MlflowClient access before assignment, please `set_mlflow_client` first!"
|
134
|
+
)
|
135
|
+
return self._mlflow_client
|
136
|
+
|
137
|
+
def set_mlflow_client(self, mlflow_client: MlflowClient):
|
138
|
+
"""
|
139
|
+
Set the mlflow_client of the agent.
|
140
|
+
"""
|
141
|
+
self._mlflow_client = mlflow_client
|
142
|
+
|
138
143
|
|
139
144
|
class InstitutionAgent(Agent):
|
140
145
|
"""
|
141
|
-
InstitutionAgent:
|
146
|
+
InstitutionAgent: Institution agent class and definition
|
142
147
|
"""
|
143
148
|
|
144
149
|
def __init__(
|
@@ -146,10 +151,10 @@ class InstitutionAgent(Agent):
|
|
146
151
|
name: str,
|
147
152
|
llm_client: Optional[LLM] = None,
|
148
153
|
simulator: Optional[Simulator] = None,
|
149
|
-
mlflow_client: Optional[MlflowClient] = None,
|
150
154
|
memory: Optional[Memory] = None,
|
151
155
|
economy_client: Optional[EconomyClient] = None,
|
152
156
|
messager: Optional[Messager] = None, # type:ignore
|
157
|
+
message_interceptor: Optional[MessageInterceptor] = None, # type:ignore
|
153
158
|
avro_file: Optional[dict] = None,
|
154
159
|
) -> None:
|
155
160
|
super().__init__(
|
@@ -157,12 +162,13 @@ class InstitutionAgent(Agent):
|
|
157
162
|
type=AgentType.Institution,
|
158
163
|
llm_client=llm_client,
|
159
164
|
economy_client=economy_client,
|
160
|
-
mlflow_client=mlflow_client,
|
161
165
|
messager=messager,
|
166
|
+
message_interceptor=message_interceptor,
|
162
167
|
simulator=simulator,
|
163
168
|
memory=memory,
|
164
169
|
avro_file=avro_file,
|
165
170
|
)
|
171
|
+
self._mlflow_client = None
|
166
172
|
# 添加响应收集器
|
167
173
|
self._gather_responses: dict[str, asyncio.Future] = {}
|
168
174
|
|
@@ -178,10 +184,10 @@ class InstitutionAgent(Agent):
|
|
178
184
|
# TODO: More general id generation
|
179
185
|
_id = random.randint(100000, 999999)
|
180
186
|
self._agent_id = _id
|
181
|
-
self.
|
187
|
+
self.status.set_agent_id(_id)
|
182
188
|
map_header = self.simulator.map.header
|
183
189
|
# TODO: remove random position assignment
|
184
|
-
await self.
|
190
|
+
await self.status.update(
|
185
191
|
"position",
|
186
192
|
{
|
187
193
|
"xy_position": {
|
@@ -201,57 +207,57 @@ class InstitutionAgent(Agent):
|
|
201
207
|
},
|
202
208
|
protect_llm_read_only_fields=False,
|
203
209
|
)
|
204
|
-
await self.
|
210
|
+
await self.status.update("id", _id, protect_llm_read_only_fields=False)
|
205
211
|
try:
|
206
212
|
await self._economy_client.remove_orgs([self._agent_id])
|
207
213
|
except:
|
208
214
|
pass
|
209
215
|
try:
|
210
|
-
|
211
|
-
_id = await
|
212
|
-
_type = await
|
216
|
+
_status = self.status
|
217
|
+
_id = await _status.get("id")
|
218
|
+
_type = await _status.get("type")
|
213
219
|
try:
|
214
|
-
nominal_gdp = await
|
220
|
+
nominal_gdp = await _status.get("nominal_gdp")
|
215
221
|
except:
|
216
222
|
nominal_gdp = []
|
217
223
|
try:
|
218
|
-
real_gdp = await
|
224
|
+
real_gdp = await _status.get("real_gdp")
|
219
225
|
except:
|
220
226
|
real_gdp = []
|
221
227
|
try:
|
222
|
-
unemployment = await
|
228
|
+
unemployment = await _status.get("unemployment")
|
223
229
|
except:
|
224
230
|
unemployment = []
|
225
231
|
try:
|
226
|
-
wages = await
|
232
|
+
wages = await _status.get("wages")
|
227
233
|
except:
|
228
234
|
wages = []
|
229
235
|
try:
|
230
|
-
prices = await
|
236
|
+
prices = await _status.get("prices")
|
231
237
|
except:
|
232
238
|
prices = []
|
233
239
|
try:
|
234
|
-
inventory = await
|
240
|
+
inventory = await _status.get("inventory")
|
235
241
|
except:
|
236
242
|
inventory = 0
|
237
243
|
try:
|
238
|
-
price = await
|
244
|
+
price = await _status.get("price")
|
239
245
|
except:
|
240
246
|
price = 0
|
241
247
|
try:
|
242
|
-
currency = await
|
248
|
+
currency = await _status.get("currency")
|
243
249
|
except:
|
244
250
|
currency = 0.0
|
245
251
|
try:
|
246
|
-
interest_rate = await
|
252
|
+
interest_rate = await _status.get("interest_rate")
|
247
253
|
except:
|
248
254
|
interest_rate = 0.0
|
249
255
|
try:
|
250
|
-
bracket_cutoffs = await
|
256
|
+
bracket_cutoffs = await _status.get("bracket_cutoffs")
|
251
257
|
except:
|
252
258
|
bracket_cutoffs = []
|
253
259
|
try:
|
254
|
-
bracket_rates = await
|
260
|
+
bracket_rates = await _status.get("bracket_rates")
|
255
261
|
except:
|
256
262
|
bracket_rates = []
|
257
263
|
await self._economy_client.add_orgs(
|
@@ -322,3 +328,18 @@ class InstitutionAgent(Agent):
|
|
322
328
|
# 清理Future
|
323
329
|
for key in futures:
|
324
330
|
self._gather_responses.pop(key, None)
|
331
|
+
|
332
|
+
@property
|
333
|
+
def mlflow_client(self) -> MlflowClient:
|
334
|
+
"""The Agent's MlflowClient"""
|
335
|
+
if self._mlflow_client is None:
|
336
|
+
raise RuntimeError(
|
337
|
+
f"MlflowClient access before assignment, please `set_mlflow_client` first!"
|
338
|
+
)
|
339
|
+
return self._mlflow_client
|
340
|
+
|
341
|
+
def set_mlflow_client(self, mlflow_client: MlflowClient):
|
342
|
+
"""
|
343
|
+
Set the mlflow_client of the agent.
|
344
|
+
"""
|
345
|
+
self._mlflow_client = mlflow_client
|
pycityagent/agent/agent_base.py
CHANGED
@@ -13,14 +13,13 @@ from typing import Any, Optional, Union, get_type_hints
|
|
13
13
|
import fastavro
|
14
14
|
import ray
|
15
15
|
from pycityproto.city.person.v2 import person_pb2 as person_pb2
|
16
|
-
from pyparsing import Dict
|
17
16
|
|
18
17
|
from ..economy import EconomyClient
|
19
18
|
from ..environment import Simulator
|
20
19
|
from ..environment.sim.person_service import PersonService
|
21
20
|
from ..llm import LLM
|
22
21
|
from ..memory import Memory
|
23
|
-
from ..message
|
22
|
+
from ..message import MessageInterceptor, Messager
|
24
23
|
from ..metrics import MlflowClient
|
25
24
|
from ..utils import DIALOG_SCHEMA, SURVEY_SCHEMA, process_survey_for_llm
|
26
25
|
from ..workflow import Block
|
@@ -48,6 +47,7 @@ class Agent(ABC):
|
|
48
47
|
|
49
48
|
configurable_fields: list[str] = []
|
50
49
|
default_values: dict[str, Any] = {}
|
50
|
+
fields_description: dict[str, str] = {}
|
51
51
|
|
52
52
|
def __init__(
|
53
53
|
self,
|
@@ -55,9 +55,9 @@ class Agent(ABC):
|
|
55
55
|
type: AgentType = AgentType.Unspecified,
|
56
56
|
llm_client: Optional[LLM] = None,
|
57
57
|
economy_client: Optional[EconomyClient] = None,
|
58
|
-
messager: Optional[
|
58
|
+
messager: Optional[ray.ObjectRef] = None,
|
59
|
+
message_interceptor: Optional[ray.ObjectRef] = None,
|
59
60
|
simulator: Optional[Simulator] = None,
|
60
|
-
mlflow_client: Optional[MlflowClient] = None,
|
61
61
|
memory: Optional[Memory] = None,
|
62
62
|
avro_file: Optional[dict[str, str]] = None,
|
63
63
|
copy_writer: Optional[ray.ObjectRef] = None,
|
@@ -72,7 +72,6 @@ class Agent(ABC):
|
|
72
72
|
economy_client (EconomyClient): The `EconomySim` client. Defaults to None.
|
73
73
|
messager (Messager, optional): The messager object. Defaults to None.
|
74
74
|
simulator (Simulator, optional): The simulator object. Defaults to None.
|
75
|
-
mlflow_client (MlflowClient, optional): The Mlflow object. Defaults to None.
|
76
75
|
memory (Memory, optional): The memory of the agent. Defaults to None.
|
77
76
|
avro_file (dict[str, str], optional): The avro file of the agent. Defaults to None.
|
78
77
|
copy_writer (ray.ObjectRef): The copy_writer of the agent. Defaults to None.
|
@@ -83,8 +82,8 @@ class Agent(ABC):
|
|
83
82
|
self._llm_client = llm_client
|
84
83
|
self._economy_client = economy_client
|
85
84
|
self._messager = messager
|
85
|
+
self._message_interceptor = message_interceptor
|
86
86
|
self._simulator = simulator
|
87
|
-
self._mlflow_client = mlflow_client
|
88
87
|
self._memory = memory
|
89
88
|
self._exp_id = -1
|
90
89
|
self._agent_id = -1
|
@@ -104,13 +103,22 @@ class Agent(ABC):
|
|
104
103
|
return state
|
105
104
|
|
106
105
|
@classmethod
|
107
|
-
def export_class_config(cls) -> dict[str,
|
108
|
-
result = {
|
106
|
+
def export_class_config(cls) -> dict[str, dict]:
|
107
|
+
result = {
|
108
|
+
"agent_name": cls.__name__,
|
109
|
+
"config": {},
|
110
|
+
"description": {},
|
111
|
+
"blocks": [],
|
112
|
+
}
|
109
113
|
config = {
|
110
114
|
field: cls.default_values.get(field, "default_value")
|
111
115
|
for field in cls.configurable_fields
|
112
116
|
}
|
113
117
|
result["config"] = config
|
118
|
+
result["description"] = {
|
119
|
+
field: cls.fields_description.get(field, "")
|
120
|
+
for field in cls.configurable_fields
|
121
|
+
}
|
114
122
|
# 解析类中的注解,找到Block类型的字段
|
115
123
|
hints = get_type_hints(cls)
|
116
124
|
for attr_name, attr_type in hints.items():
|
@@ -119,14 +127,15 @@ class Agent(ABC):
|
|
119
127
|
result["blocks"].append(
|
120
128
|
{
|
121
129
|
"name": attr_name,
|
122
|
-
"config": block_config,
|
130
|
+
"config": block_config[0], # type:ignore
|
131
|
+
"description": block_config[1], # type:ignore
|
123
132
|
"children": cls._export_subblocks(attr_type),
|
124
133
|
}
|
125
134
|
)
|
126
135
|
return result
|
127
136
|
|
128
137
|
@classmethod
|
129
|
-
def _export_subblocks(cls, block_cls: type[Block]) -> list[
|
138
|
+
def _export_subblocks(cls, block_cls: type[Block]) -> list[dict]:
|
130
139
|
children = []
|
131
140
|
hints = get_type_hints(block_cls) # 获取类的注解
|
132
141
|
for attr_name, attr_type in hints.items():
|
@@ -135,7 +144,8 @@ class Agent(ABC):
|
|
135
144
|
children.append(
|
136
145
|
{
|
137
146
|
"name": attr_name,
|
138
|
-
"config": block_config,
|
147
|
+
"config": block_config[0], # type:ignore
|
148
|
+
"description": block_config[1], # type:ignore
|
139
149
|
"children": cls._export_subblocks(attr_type),
|
140
150
|
}
|
141
151
|
)
|
@@ -216,12 +226,6 @@ class Agent(ABC):
|
|
216
226
|
"""
|
217
227
|
self._simulator = simulator
|
218
228
|
|
219
|
-
def set_mlflow_client(self, mlflow_client: MlflowClient):
|
220
|
-
"""
|
221
|
-
Set the mlflow_client of the agent.
|
222
|
-
"""
|
223
|
-
self._mlflow_client = mlflow_client
|
224
|
-
|
225
229
|
def set_economy_client(self, economy_client: EconomyClient):
|
226
230
|
"""
|
227
231
|
Set the economy_client of the agent.
|
@@ -252,6 +256,12 @@ class Agent(ABC):
|
|
252
256
|
"""
|
253
257
|
self._pgsql_writer = pgsql_writer
|
254
258
|
|
259
|
+
def set_message_interceptor(self, message_interceptor: ray.ObjectRef):
|
260
|
+
"""
|
261
|
+
Set the PostgreSQL copy writer of the agent.
|
262
|
+
"""
|
263
|
+
self._message_interceptor = message_interceptor
|
264
|
+
|
255
265
|
@property
|
256
266
|
def uuid(self):
|
257
267
|
"""The Agent's UUID"""
|
@@ -279,16 +289,7 @@ class Agent(ABC):
|
|
279
289
|
f"EconomyClient access before assignment, please `set_economy_client` first!"
|
280
290
|
)
|
281
291
|
return self._economy_client
|
282
|
-
|
283
|
-
@property
|
284
|
-
def mlflow_client(self):
|
285
|
-
"""The Agent's MlflowClient"""
|
286
|
-
if self._mlflow_client is None:
|
287
|
-
raise RuntimeError(
|
288
|
-
f"MlflowClient access before assignment, please `set_mlflow_client` first!"
|
289
|
-
)
|
290
|
-
return self._mlflow_client
|
291
|
-
|
292
|
+
|
292
293
|
@property
|
293
294
|
def memory(self):
|
294
295
|
"""The Agent's Memory"""
|
@@ -298,6 +299,24 @@ class Agent(ABC):
|
|
298
299
|
)
|
299
300
|
return self._memory
|
300
301
|
|
302
|
+
@property
|
303
|
+
def status(self):
|
304
|
+
"""The Agent's Status Memory"""
|
305
|
+
if self.memory.status is None:
|
306
|
+
raise RuntimeError(
|
307
|
+
f"Status access before assignment, please `set_memory` first!"
|
308
|
+
)
|
309
|
+
return self.memory.status
|
310
|
+
|
311
|
+
@property
|
312
|
+
def stream(self):
|
313
|
+
"""The Agent's Stream Memory"""
|
314
|
+
if self.memory.stream is None:
|
315
|
+
raise RuntimeError(
|
316
|
+
f"Stream access before assignment, please `set_memory` first!"
|
317
|
+
)
|
318
|
+
return self.memory.stream
|
319
|
+
|
301
320
|
@property
|
302
321
|
def simulator(self):
|
303
322
|
"""The Simulator"""
|
@@ -315,11 +334,17 @@ class Agent(ABC):
|
|
315
334
|
f"Copy Writer access before assignment, please `set_pgsql_writer` first!"
|
316
335
|
)
|
317
336
|
return self._pgsql_writer
|
337
|
+
|
338
|
+
@property
|
339
|
+
def messager(self):
|
340
|
+
if self._messager is None:
|
341
|
+
raise RuntimeError("Messager is not set")
|
342
|
+
return self._messager
|
318
343
|
|
319
344
|
async def messager_ping(self):
|
320
345
|
if self._messager is None:
|
321
346
|
raise RuntimeError("Messager is not set")
|
322
|
-
return await self._messager.ping()
|
347
|
+
return await self._messager.ping.remote() # type:ignore
|
323
348
|
|
324
349
|
async def generate_user_survey_response(self, survey: dict) -> str:
|
325
350
|
"""生成回答 —— 可重写
|
@@ -338,22 +363,15 @@ class Agent(ABC):
|
|
338
363
|
|
339
364
|
# 添加记忆上下文
|
340
365
|
if self._memory:
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
if relevant_memories:
|
351
|
-
dialog.append(
|
352
|
-
{
|
353
|
-
"role": "system",
|
354
|
-
"content": f"Answer based on these memories:\n{relevant_memories}",
|
355
|
-
}
|
356
|
-
)
|
366
|
+
profile_and_states = await self.status.search(survey_prompt)
|
367
|
+
relevant_activities = await self.stream.search(survey_prompt)
|
368
|
+
|
369
|
+
dialog.append(
|
370
|
+
{
|
371
|
+
"role": "system",
|
372
|
+
"content": f"Answer based on following profile and states:\n{profile_and_states}\n Related activities:\n{relevant_activities}",
|
373
|
+
}
|
374
|
+
)
|
357
375
|
|
358
376
|
# 添加问卷问题
|
359
377
|
dialog.append({"role": "user", "content": survey_prompt})
|
@@ -412,6 +430,7 @@ class Agent(ABC):
|
|
412
430
|
_data_tuples
|
413
431
|
)
|
414
432
|
)
|
433
|
+
await self.messager.send_message.remote(f"exps/{self._exp_id}/user_payback", {"count": 1})# type:ignore
|
415
434
|
|
416
435
|
async def generate_user_chat_response(self, question: str) -> str:
|
417
436
|
"""生成回答 —— 可重写
|
@@ -430,14 +449,15 @@ class Agent(ABC):
|
|
430
449
|
|
431
450
|
# 添加记忆上下文
|
432
451
|
if self._memory:
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
}
|
440
|
-
|
452
|
+
profile_and_states = await self.status.search(question, top_k=10)
|
453
|
+
relevant_activities = await self.stream.search(question, top_k=10)
|
454
|
+
|
455
|
+
dialog.append(
|
456
|
+
{
|
457
|
+
"role": "system",
|
458
|
+
"content": f"Answer based on following profile and states:\n{profile_and_states}\n Related activities:\n{relevant_activities}",
|
459
|
+
}
|
460
|
+
)
|
441
461
|
|
442
462
|
# 添加用户问题
|
443
463
|
dialog.append({"role": "user", "content": question})
|
@@ -497,6 +517,8 @@ class Agent(ABC):
|
|
497
517
|
_data
|
498
518
|
)
|
499
519
|
)
|
520
|
+
await self.messager.send_message.remote(f"exps/{self._exp_id}/user_payback", {"count": 1})# type:ignore
|
521
|
+
print(f"Sent payback message to {self._exp_id}")
|
500
522
|
|
501
523
|
async def process_agent_chat_response(self, payload: dict) -> str:
|
502
524
|
resp = f"Agent {self._uuid} received agent chat response: {payload}"
|
@@ -566,7 +588,12 @@ class Agent(ABC):
|
|
566
588
|
if self._messager is None:
|
567
589
|
raise RuntimeError("Messager is not set")
|
568
590
|
topic = f"exps/{self._exp_id}/agents/{to_agent_uuid}/{sub_topic}"
|
569
|
-
await self._messager.send_message.remote(
|
591
|
+
await self._messager.send_message.remote( # type:ignore
|
592
|
+
topic,
|
593
|
+
payload,
|
594
|
+
self._uuid,
|
595
|
+
to_agent_uuid,
|
596
|
+
)
|
570
597
|
|
571
598
|
async def send_message_to_agent(
|
572
599
|
self, to_agent_uuid: str, content: str, type: str = "social"
|
@@ -630,6 +657,6 @@ class Agent(ABC):
|
|
630
657
|
当_blocked为True时,不执行forward方法
|
631
658
|
"""
|
632
659
|
if self._messager is not None:
|
633
|
-
await self._messager.ping.remote()
|
660
|
+
await self._messager.ping.remote() # type:ignore
|
634
661
|
if not self._blocked:
|
635
662
|
await self.forward()
|
@@ -53,14 +53,12 @@ class BankAgent(InstitutionAgent):
|
|
53
53
|
|
54
54
|
async def forward(self):
|
55
55
|
if await self.month_trigger():
|
56
|
-
citizens = await self.memory.get("citizens")
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
break
|
61
|
-
await asyncio.sleep(1)
|
56
|
+
citizens = await self.memory.status.get("citizens")
|
57
|
+
agents_forward = []
|
58
|
+
if not np.all(np.array(agents_forward) > self.forward_times):
|
59
|
+
return
|
62
60
|
self.forward_times += 1
|
63
61
|
for uuid in citizens:
|
64
62
|
await self.send_message_to_agent(
|
65
|
-
uuid, f"bank_forward@{self.forward_times}"
|
63
|
+
uuid, f"bank_forward@{self.forward_times}", "economy"
|
66
64
|
)
|
@@ -5,7 +5,6 @@ from .needs_block import NeedsBlock
|
|
5
5
|
from .social_block import SocialBlock
|
6
6
|
from .economy_block import EconomyBlock
|
7
7
|
from .other_block import OtherBlock
|
8
|
-
from .time_block import TimeBlock
|
9
8
|
|
10
9
|
__all__ = [
|
11
10
|
"MobilityBlock",
|
@@ -16,5 +15,4 @@ __all__ = [
|
|
16
15
|
"EconomyBlock",
|
17
16
|
"OtherBlock",
|
18
17
|
"LongTermDecisionBlock",
|
19
|
-
"TimeBlock",
|
20
18
|
]
|