pycityagent 2.0.0a52__cp39-cp39-macosx_11_0_arm64.whl → 2.0.0a54__cp39-cp39-macosx_11_0_arm64.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. pycityagent/agent/agent.py +83 -62
  2. pycityagent/agent/agent_base.py +81 -54
  3. pycityagent/cityagent/bankagent.py +5 -7
  4. pycityagent/cityagent/blocks/__init__.py +0 -2
  5. pycityagent/cityagent/blocks/cognition_block.py +149 -172
  6. pycityagent/cityagent/blocks/economy_block.py +90 -129
  7. pycityagent/cityagent/blocks/mobility_block.py +56 -29
  8. pycityagent/cityagent/blocks/needs_block.py +163 -145
  9. pycityagent/cityagent/blocks/other_block.py +17 -9
  10. pycityagent/cityagent/blocks/plan_block.py +45 -57
  11. pycityagent/cityagent/blocks/social_block.py +70 -51
  12. pycityagent/cityagent/blocks/utils.py +2 -0
  13. pycityagent/cityagent/firmagent.py +6 -7
  14. pycityagent/cityagent/governmentagent.py +7 -9
  15. pycityagent/cityagent/memory_config.py +48 -48
  16. pycityagent/cityagent/message_intercept.py +99 -0
  17. pycityagent/cityagent/nbsagent.py +6 -29
  18. pycityagent/cityagent/societyagent.py +325 -127
  19. pycityagent/cli/wrapper.py +4 -0
  20. pycityagent/economy/econ_client.py +0 -2
  21. pycityagent/environment/__init__.py +7 -1
  22. pycityagent/environment/sim/client.py +10 -1
  23. pycityagent/environment/sim/clock_service.py +2 -2
  24. pycityagent/environment/sim/pause_service.py +61 -0
  25. pycityagent/environment/sim/sim_env.py +34 -46
  26. pycityagent/environment/simulator.py +18 -14
  27. pycityagent/llm/embeddings.py +0 -24
  28. pycityagent/llm/llm.py +18 -10
  29. pycityagent/memory/faiss_query.py +29 -26
  30. pycityagent/memory/memory.py +733 -247
  31. pycityagent/message/__init__.py +8 -1
  32. pycityagent/message/message_interceptor.py +322 -0
  33. pycityagent/message/messager.py +42 -11
  34. pycityagent/pycityagent-sim +0 -0
  35. pycityagent/simulation/agentgroup.py +137 -96
  36. pycityagent/simulation/simulation.py +184 -38
  37. pycityagent/simulation/storage/pg.py +2 -2
  38. pycityagent/tools/tool.py +7 -9
  39. pycityagent/utils/__init__.py +7 -2
  40. pycityagent/utils/pg_query.py +1 -0
  41. pycityagent/utils/survey_util.py +26 -23
  42. pycityagent/workflow/block.py +14 -7
  43. {pycityagent-2.0.0a52.dist-info → pycityagent-2.0.0a54.dist-info}/METADATA +2 -2
  44. {pycityagent-2.0.0a52.dist-info → pycityagent-2.0.0a54.dist-info}/RECORD +48 -46
  45. pycityagent/cityagent/blocks/time_block.py +0 -116
  46. {pycityagent-2.0.0a52.dist-info → pycityagent-2.0.0a54.dist-info}/LICENSE +0 -0
  47. {pycityagent-2.0.0a52.dist-info → pycityagent-2.0.0a54.dist-info}/WHEEL +0 -0
  48. {pycityagent-2.0.0a52.dist-info → pycityagent-2.0.0a54.dist-info}/entry_points.txt +0 -0
  49. {pycityagent-2.0.0a52.dist-info → pycityagent-2.0.0a54.dist-info}/top_level.txt +0 -0
@@ -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.messager import Messager
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
- if not self._has_bound_to_simulator:
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
- memory = self.memory
77
- person_id = await memory.get("id")
78
- # ATTENTION:模拟器分配的id从0开始
79
- if person_id >= 0:
80
- await simulator.get_person(person_id)
81
- logger.debug(f"Binding to Person `{person_id}` already in Simulator")
82
- else:
83
- dict_person = deepcopy(self._person_template)
84
- for _key in FROM_MEMORY_KEYS:
85
- try:
86
- _value = await memory.get(_key)
87
- if _value:
88
- dict_person[_key] = _value
89
- except KeyError as e:
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.memory.get("id")
113
- currency = await self.memory.get("currency")
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.memory.get(f"{target}")
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.memory.set_agent_id(_id)
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.memory.update(
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.memory.update("id", _id, protect_llm_read_only_fields=False)
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
- _memory = self.memory
211
- _id = await _memory.get("id")
212
- _type = await _memory.get("type")
216
+ _status = self.status
217
+ _id = await _status.get("id")
218
+ _type = await _status.get("type")
213
219
  try:
214
- nominal_gdp = await _memory.get("nominal_gdp")
220
+ nominal_gdp = await _status.get("nominal_gdp")
215
221
  except:
216
222
  nominal_gdp = []
217
223
  try:
218
- real_gdp = await _memory.get("real_gdp")
224
+ real_gdp = await _status.get("real_gdp")
219
225
  except:
220
226
  real_gdp = []
221
227
  try:
222
- unemployment = await _memory.get("unemployment")
228
+ unemployment = await _status.get("unemployment")
223
229
  except:
224
230
  unemployment = []
225
231
  try:
226
- wages = await _memory.get("wages")
232
+ wages = await _status.get("wages")
227
233
  except:
228
234
  wages = []
229
235
  try:
230
- prices = await _memory.get("prices")
236
+ prices = await _status.get("prices")
231
237
  except:
232
238
  prices = []
233
239
  try:
234
- inventory = await _memory.get("inventory")
240
+ inventory = await _status.get("inventory")
235
241
  except:
236
242
  inventory = 0
237
243
  try:
238
- price = await _memory.get("price")
244
+ price = await _status.get("price")
239
245
  except:
240
246
  price = 0
241
247
  try:
242
- currency = await _memory.get("currency")
248
+ currency = await _status.get("currency")
243
249
  except:
244
250
  currency = 0.0
245
251
  try:
246
- interest_rate = await _memory.get("interest_rate")
252
+ interest_rate = await _status.get("interest_rate")
247
253
  except:
248
254
  interest_rate = 0.0
249
255
  try:
250
- bracket_cutoffs = await _memory.get("bracket_cutoffs")
256
+ bracket_cutoffs = await _status.get("bracket_cutoffs")
251
257
  except:
252
258
  bracket_cutoffs = []
253
259
  try:
254
- bracket_rates = await _memory.get("bracket_rates")
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
@@ -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.messager import Messager
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[Messager] = None, # type:ignore
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, Dict]:
108
- result = {"agent_name": cls.__name__, "config": {}, "blocks": []}
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[Dict]:
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
- relevant_memories = await self.memory.search(survey_prompt)
342
-
343
- formatted_results = []
344
- # for result in top_results:
345
- # formatted_results.append(
346
- # f"- [{result['type']}] {result['content']} "
347
- # f"(相关度: {result['similarity']:.2f})"
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
- relevant_memories = await self._memory.search(question)
434
- if relevant_memories:
435
- dialog.append(
436
- {
437
- "role": "system",
438
- "content": f"Answer based on these memories:\n{relevant_memories}",
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(topic, payload)
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
- while True:
58
- agents_forward = await self.gather_messages(citizens, "forward")
59
- if np.all(np.array(agents_forward) > self.forward_times):
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
  ]