pycityagent 2.0.0a52__cp311-cp311-macosx_11_0_arm64.whl → 2.0.0a54__cp311-cp311-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
@@ -8,9 +8,8 @@ from pycityagent.agent import Agent
8
8
  from pycityagent.economy import EconomyClient
9
9
  from pycityagent.llm.llm import LLM
10
10
  from pycityagent.memory import Memory
11
- from pycityagent.message import Messager
12
- from pycityagent.workflow import Block
13
11
  from pycityagent.tools import UpdateWithSimulator
12
+ from pycityagent.workflow import Block
14
13
 
15
14
  from .blocks import (CognitionBlock, EconomyBlock, MobilityBlock, NeedsBlock,
16
15
  OtherBlock, PlanBlock, SocialBlock)
@@ -20,7 +19,7 @@ logger = logging.getLogger("pycityagent")
20
19
 
21
20
 
22
21
  class PlanAndActionBlock(Block):
23
- """主动工作流"""
22
+ """Active workflow based on needs model and plan behavior model"""
24
23
 
25
24
  longTermDecisionBlock: MonthPlanBlock
26
25
  needsBlock: NeedsBlock
@@ -55,87 +54,22 @@ class PlanAndActionBlock(Block):
55
54
  llm=llm, memory=memory, simulator=simulator, economy_client=economy_client
56
55
  )
57
56
  self.otherBlock = OtherBlock(llm=llm, memory=memory)
58
-
59
- async def check_and_update_step(self):
60
- status = await self.memory.get("status")
61
- if status == 2:
62
- # 正在运动
63
- logger.info("Agent is moving")
64
- await asyncio.sleep(1)
65
- return False
66
-
67
- # 获取上一步信息
68
- current_step = await self.memory.get("current_step")
69
- if current_step["intention"] == "" or current_step["type"] == "":
70
- # 没有上一步,直接返回
71
- return True
72
- time_now = int(await self.simulator.get_time())
73
- step_start_time = current_step["start_time"]
74
- step_consumed_time = current_step["evaluation"]["consumed_time"]
75
- time_end_plan = step_start_time + int(step_consumed_time) * 60
76
- if time_now >= time_end_plan:
77
- # 上一步执行完成
78
- current_plan = await self.memory.get("current_plan")
79
- current_step["evaluation"]["consumed_time"] = (
80
- time_now - step_start_time
81
- ) / 60
82
- current_step_index = next(
83
- (
84
- i
85
- for i, step in enumerate(current_plan["steps"])
86
- if step["intention"] == current_step["intention"]
87
- and step["type"] == current_step["type"]
88
- ),
89
- None,
90
- )
91
- current_plan["steps"][current_step_index] = current_step
92
- await self.memory.update("current_plan", current_plan)
93
- if current_step_index is not None and current_step_index + 1 < len(
94
- current_plan["steps"]
95
- ):
96
- next_step = current_plan["steps"][current_step_index + 1]
97
- await self.memory.update("current_step", next_step)
98
- else:
99
- # 标记计划完成
100
- current_plan["completed"] = True
101
- current_plan["end_time"] = await self.simulator.get_time(
102
- format_time=True
103
- )
104
- await self.memory.update("current_plan", current_plan)
105
- await self.memory.update("current_step", {"intention": "", "type": ""})
106
- logger.info("Current plan execution completed.\n")
107
- return True
108
- # 上一步未执行完成
109
- return False
110
-
111
- async def forward(self):
112
- # 与模拟器同步智能体的状态
113
- await self._agent.update_with_sim()
114
- # 检测上一步是否执行完成
115
- if not await self.check_and_update_step():
116
- return
117
-
118
- # 长期决策
119
- await self.longTermDecisionBlock.forward()
120
-
121
- # 需求更新
122
- time_now = await self.simulator.get_time(format_time=True)
123
- logger.info(f"Current time: {time_now}")
124
- await self.needsBlock.forward()
125
- current_need = await self.memory.get("current_need")
126
- logger.info(f"Current need: {current_need}")
127
-
128
- # 计划生成
129
- current_plan = await self.memory.get("current_plan")
57
+ async def plan_generation(self):
58
+ """Generate plan"""
59
+ current_plan = await self.memory.status.get("current_plan")
60
+ current_need = await self.memory.status.get("current_need")
130
61
  if current_need != "none" and not current_plan:
131
62
  await self.planBlock.forward()
132
- current_plan = await self.memory.get("current_plan")
133
- execution_context = await self.memory.get("execution_context")
134
- current_step = await self.memory.get("current_step")
135
- # 检查 current_step 是否有效(不为空)
63
+
64
+ async def step_execution(self):
65
+ """Execute the current step"""
66
+ current_plan = await self.memory.status.get("current_plan")
67
+ execution_context = await self.memory.status.get("execution_context")
68
+ current_step = await self.memory.status.get("current_step")
69
+ # check current_step is valid (not empty)
136
70
  if current_step and current_step.get("type") and current_step.get("intention"):
137
71
  step_type = current_step.get("type")
138
- position = await self.memory.get("position")
72
+ position = await self.memory.status.get("position")
139
73
  if "aoi_position" in position:
140
74
  current_step["position"] = position["aoi_position"]["aoi_id"]
141
75
  current_step["start_time"] = int(await self.simulator.get_time())
@@ -144,22 +78,48 @@ class PlanAndActionBlock(Block):
144
78
  )
145
79
  result = None
146
80
  if step_type == "mobility":
147
- result = await self.mobilityBlock.forward(
148
- current_step, execution_context
149
- )
81
+ if self.enable_mobility: # type:ignore
82
+ result = await self.mobilityBlock.forward(
83
+ current_step, execution_context
84
+ )
85
+ else:
86
+ result = {
87
+ "success": False,
88
+ "evaluation": f"Mobility Behavior is disabled",
89
+ "consumed_time": 0,
90
+ "node_id": None,
91
+ }
150
92
  elif step_type == "social":
151
- result = await self.socialBlock.forward(current_step, execution_context)
93
+ if self.enable_social: # type:ignore
94
+ result = await self.socialBlock.forward(
95
+ current_step, execution_context
96
+ )
97
+ else:
98
+ result = {
99
+ "success": False,
100
+ "evaluation": f"Social Behavior is disabled",
101
+ "consumed_time": 0,
102
+ "node_id": None,
103
+ }
152
104
  elif step_type == "economy":
153
- result = await self.economyBlock.forward(
154
- current_step, execution_context
155
- )
105
+ if self.enable_economy: # type:ignore
106
+ result = await self.economyBlock.forward(
107
+ current_step, execution_context
108
+ )
109
+ else:
110
+ result = {
111
+ "success": False,
112
+ "evaluation": f"Economy Behavior is disabled",
113
+ "consumed_time": 0,
114
+ "node_id": None,
115
+ }
156
116
  elif step_type == "other":
157
117
  result = await self.otherBlock.forward(current_step, execution_context)
158
118
  if result != None:
159
119
  logger.info(f"Execution result: {result}")
160
120
  current_step["evaluation"] = result
161
121
 
162
- # 更新current_step信息,plan信息以及execution_context信息
122
+ # Update current_step, plan, and execution_context information
163
123
  current_step_index = next(
164
124
  (
165
125
  i
@@ -170,30 +130,58 @@ class PlanAndActionBlock(Block):
170
130
  None,
171
131
  )
172
132
  current_plan["steps"][current_step_index] = current_step
173
- await self.memory.update("current_step", current_step)
174
- await self.memory.update("current_plan", current_plan)
175
- await self.memory.update("execution_context", execution_context)
133
+ await self.memory.status.update("current_step", current_step)
134
+ await self.memory.status.update("current_plan", current_plan)
135
+ await self.memory.status.update("execution_context", execution_context)
136
+
137
+ async def forward(self):
138
+ # Long-term decision
139
+ await self.longTermDecisionBlock.forward()
140
+
141
+ # update needs
142
+ await self.needsBlock.forward()
176
143
 
144
+ # plan generation
145
+ await self.plan_generation()
177
146
 
178
- class MindBlock(Block):
179
- """认知工作流"""
147
+ # step execution
148
+ await self.step_execution()
180
149
 
150
+ class MindBlock(Block):
151
+ """Cognition workflow"""
181
152
  cognitionBlock: CognitionBlock
182
153
 
183
154
  def __init__(self, llm: LLM, memory: Memory, simulator: Simulator):
184
155
  super().__init__(name="mind_block", llm=llm, memory=memory, simulator=simulator)
185
156
  self.cognitionBlock = CognitionBlock(
186
- llm=llm, memory=memory, simulator=simulator
157
+ llm=self.llm, memory=self.memory, simulator=simulator
187
158
  )
188
159
 
189
160
  async def forward(self):
190
161
  await self.cognitionBlock.forward()
191
162
 
192
-
193
163
  class SocietyAgent(CitizenAgent):
194
164
  mindBlock: MindBlock
195
165
  planAndActionBlock: PlanAndActionBlock
196
166
  update_with_sim = UpdateWithSimulator()
167
+ configurable_fields = [
168
+ "enable_cognition",
169
+ "enable_mobility",
170
+ "enable_social",
171
+ "enable_economy",
172
+ ]
173
+ default_values = {
174
+ "enable_cognition": True,
175
+ "enable_mobility": True,
176
+ "enable_social": True,
177
+ "enable_economy": True,
178
+ }
179
+ fields_description = {
180
+ "enable_cognition": "Enable cognition workflow",
181
+ "enable_mobility": "Enable mobility workflow",
182
+ "enable_social": "Enable social workflow",
183
+ "enable_economy": "Enable economy workflow",
184
+ }
197
185
 
198
186
  def __init__(
199
187
  self,
@@ -211,29 +199,224 @@ class SocietyAgent(CitizenAgent):
211
199
  economy_client=economy_client,
212
200
  )
213
201
  self.mindBlock = MindBlock(
214
- llm=self._llm_client, memory=self._memory, simulator=self._simulator
202
+ llm=self.llm, memory=self.memory, simulator=self.simulator
215
203
  )
216
204
  self.planAndActionBlock = PlanAndActionBlock(
217
205
  agent=self,
218
- llm=self._llm_client,
219
- memory=self._memory,
220
- simulator=self._simulator,
221
- economy_client=self._economy_client,
206
+ llm=self.llm,
207
+ memory=self.memory,
208
+ simulator=self.simulator,
209
+ economy_client=self.economy_client,
222
210
  )
223
211
  self.step_count = -1
212
+ self.cognition_update = -1
213
+
214
+ # config
215
+ self.enable_cognition = True
216
+ self.enable_mobility = True
217
+ self.enable_social = True
218
+ self.enable_economy = True
224
219
 
225
220
  # Main workflow
226
221
  async def forward(self):
227
- logger.info(f"Agent {self._uuid} forward")
228
222
  self.step_count += 1
229
- # 多工作流并发执行
230
- task_list = [
231
- asyncio.create_task(self.mindBlock.forward()),
232
- asyncio.create_task(self.planAndActionBlock.forward()),
233
- ]
234
- await asyncio.gather(*task_list)
235
-
236
- async def process_agent_chat_response(self, payload: dict) -> str:
223
+ logger.info(f"Agent {self._uuid} forward [step_count: {self.step_count}]")
224
+ # sync agent status with simulator
225
+ await self.update_with_sim()
226
+
227
+ # check last step
228
+ if not await self.check_and_update_step():
229
+ return
230
+
231
+ await self.planAndActionBlock.forward()
232
+
233
+ if self.enable_cognition:
234
+ await self.mindBlock.forward()
235
+
236
+ async def check_and_update_step(self):
237
+ """Check if the previous step has been completed"""
238
+ status = await self.memory.status.get("status")
239
+ if status == 2:
240
+ # Agent is moving
241
+ logger.info("Agent is moving")
242
+ await asyncio.sleep(1)
243
+ return False
244
+
245
+ # Get the previous step information
246
+ current_step = await self.memory.status.get("current_step")
247
+ if current_step["intention"] == "" or current_step["type"] == "":
248
+ # No previous step, return directly
249
+ return True
250
+ time_now = int(await self.simulator.get_time())
251
+ step_start_time = current_step["start_time"]
252
+ step_consumed_time = current_step["evaluation"]["consumed_time"]
253
+ time_end_plan = step_start_time + int(step_consumed_time) * 60
254
+ if time_now >= time_end_plan:
255
+ # The previous step has been completed
256
+ current_plan = await self.memory.status.get("current_plan")
257
+ current_step["evaluation"]["consumed_time"] = (
258
+ time_now - step_start_time
259
+ ) / 60
260
+ current_plan["stream_nodes"].append(current_step["evaluation"]["node_id"])
261
+ if current_step["evaluation"]["success"]:
262
+ # Last step is completed
263
+ current_step_index = next(
264
+ (
265
+ i
266
+ for i, step in enumerate(current_plan["steps"])
267
+ if step["intention"] == current_step["intention"]
268
+ and step["type"] == current_step["type"]
269
+ ),
270
+ None,
271
+ )
272
+ current_plan["steps"][current_step_index] = current_step
273
+ await self.memory.status.update("current_plan", current_plan)
274
+ if current_step_index is not None and current_step_index + 1 < len(
275
+ current_plan["steps"]
276
+ ):
277
+ next_step = current_plan["steps"][current_step_index + 1]
278
+ await self.memory.status.update("current_step", next_step)
279
+ else:
280
+ # Whole plan is completed
281
+ current_plan["completed"] = True
282
+ current_plan["end_time"] = await self.simulator.get_time(
283
+ format_time=True
284
+ )
285
+ if self.enable_cognition:
286
+ # Update emotion for the plan
287
+ related_memories = await self.memory.stream.get_by_ids(current_plan["stream_nodes"])
288
+ incident = f"You have successfully completed the plan: {related_memories}"
289
+ conclusion = await self.mindBlock.cognitionBlock.emotion_update(incident)
290
+ await self.memory.stream.add_cognition(description=conclusion)
291
+ await self.memory.stream.add_cognition_to_memory(current_plan["stream_nodes"], conclusion)
292
+ await self.memory.status.update("current_plan", current_plan)
293
+ await self.memory.status.update("current_step", {"intention": "", "type": ""})
294
+ return True
295
+ else:
296
+ current_plan["failed"] = True
297
+ current_plan["end_time"] = await self.simulator.get_time(
298
+ format_time=True
299
+ )
300
+ if self.enable_cognition:
301
+ # Update emotion for the plan
302
+ related_memories = await self.memory.stream.get_by_ids(current_plan["stream_nodes"])
303
+ incident = f"You have failed to complete the plan: {related_memories}"
304
+ conclusion = await self.mindBlock.cognitionBlock.emotion_update(incident)
305
+ await self.memory.stream.add_cognition(description=conclusion)
306
+ await self.memory.stream.add_cognition_to_memory(current_plan["stream_nodes"], conclusion)
307
+ await self.memory.status.update("current_plan", current_plan)
308
+ await self.memory.status.update("current_step", {"intention": "", "type": ""})
309
+ # The previous step has not been completed
310
+ return False
311
+
312
+ # check last step
313
+ if not await self.check_and_update_step():
314
+ return
315
+
316
+ await self.planAndActionBlock.forward()
317
+
318
+ if self.enable_cognition:
319
+ await self.mindBlock.forward()
320
+
321
+ async def check_and_update_step(self):
322
+ """Check if the previous step has been completed"""
323
+ status = await self.memory.status.get("status")
324
+ if status == 2:
325
+ # Agent is moving
326
+ logger.info("Agent is moving")
327
+ await asyncio.sleep(1)
328
+ return False
329
+
330
+ # Get the previous step information
331
+ current_step = await self.memory.status.get("current_step")
332
+ if current_step["intention"] == "" or current_step["type"] == "":
333
+ # No previous step, return directly
334
+ return True
335
+ time_now = int(await self.simulator.get_time())
336
+ step_start_time = current_step["start_time"]
337
+ step_consumed_time = current_step["evaluation"]["consumed_time"]
338
+ time_end_plan = step_start_time + int(step_consumed_time) * 60
339
+ if time_now >= time_end_plan:
340
+ # The previous step has been completed
341
+ current_plan = await self.memory.status.get("current_plan")
342
+ current_step["evaluation"]["consumed_time"] = (
343
+ time_now - step_start_time
344
+ ) / 60
345
+ current_plan["stream_nodes"].append(current_step["evaluation"]["node_id"])
346
+ if current_step["evaluation"]["success"]:
347
+ # Last step is completed
348
+ current_step_index = next(
349
+ (
350
+ i
351
+ for i, step in enumerate(current_plan["steps"])
352
+ if step["intention"] == current_step["intention"]
353
+ and step["type"] == current_step["type"]
354
+ ),
355
+ None,
356
+ )
357
+ current_plan["steps"][current_step_index] = current_step
358
+ await self.memory.status.update("current_plan", current_plan)
359
+ if current_step_index is not None and current_step_index + 1 < len(
360
+ current_plan["steps"]
361
+ ):
362
+ next_step = current_plan["steps"][current_step_index + 1]
363
+ await self.memory.status.update("current_step", next_step)
364
+ else:
365
+ # Whole plan is completed
366
+ current_plan["completed"] = True
367
+ current_plan["end_time"] = await self.simulator.get_time(
368
+ format_time=True
369
+ )
370
+ if self.enable_cognition:
371
+ # Update emotion for the plan
372
+ related_memories = await self.memory.stream.get_by_ids(
373
+ current_plan["stream_nodes"]
374
+ )
375
+ incident = f"You have successfully completed the plan: {related_memories}"
376
+ conclusion = await self.mindBlock.cognitionBlock.emotion_update(
377
+ incident
378
+ )
379
+ await self.memory.stream.add_cognition(
380
+ description=conclusion # type:ignore
381
+ )
382
+ await self.memory.stream.add_cognition_to_memory(
383
+ current_plan["stream_nodes"], conclusion # type:ignore
384
+ )
385
+ await self.memory.status.update("current_plan", current_plan)
386
+ await self.memory.status.update(
387
+ "current_step", {"intention": "", "type": ""}
388
+ )
389
+ return True
390
+ else:
391
+ current_plan["failed"] = True
392
+ current_plan["end_time"] = await self.simulator.get_time(
393
+ format_time=True
394
+ )
395
+ if self.enable_cognition:
396
+ # Update emotion for the plan
397
+ related_memories = await self.memory.stream.get_by_ids(
398
+ current_plan["stream_nodes"]
399
+ )
400
+ incident = (
401
+ f"You have failed to complete the plan: {related_memories}"
402
+ )
403
+ conclusion = await self.mindBlock.cognitionBlock.emotion_update(
404
+ incident
405
+ )
406
+ await self.memory.stream.add_cognition(
407
+ description=conclusion # type:ignore
408
+ )
409
+ await self.memory.stream.add_cognition_to_memory(
410
+ current_plan["stream_nodes"], conclusion # type:ignore
411
+ )
412
+ await self.memory.status.update("current_plan", current_plan)
413
+ await self.memory.status.update(
414
+ "current_step", {"intention": "", "type": ""}
415
+ )
416
+ # The previous step has not been completed
417
+ return False
418
+
419
+ async def process_agent_chat_response(self, payload: dict) -> str: # type:ignore
237
420
  if payload["type"] == "social":
238
421
  resp = f"Agent {self._uuid} received agent chat response: {payload}"
239
422
  logger.info(resp)
@@ -256,9 +439,16 @@ class SocietyAgent(CitizenAgent):
256
439
 
257
440
  if not content:
258
441
  return ""
442
+
443
+ # 添加记忆
444
+ description = f"You received a social message: {content}"
445
+ await self.memory.stream.add_social(description=description)
446
+ if self.enable_cognition:
447
+ # 更新情绪
448
+ await self.mindBlock.cognitionBlock.emotion_update(description)
259
449
 
260
450
  # Get chat histories and ensure proper format
261
- chat_histories = await self._memory.get("chat_histories") or {}
451
+ chat_histories = await self.memory.status.get("chat_histories") or {}
262
452
  if not isinstance(chat_histories, dict):
263
453
  chat_histories = {}
264
454
 
@@ -271,14 +461,14 @@ class SocietyAgent(CitizenAgent):
271
461
 
272
462
  # Check propagation limit
273
463
  if propagation_count > 5:
274
- await self._memory.update("chat_histories", chat_histories)
464
+ await self.memory.status.update("chat_histories", chat_histories)
275
465
  logger.info(
276
466
  f"Message propagation limit reached ({propagation_count} > 5), stopping propagation"
277
467
  )
278
468
  return ""
279
469
 
280
470
  # Get relationship score
281
- relationships = await self._memory.get("relationships") or {}
471
+ relationships = await self.memory.status.get("relationships") or {}
282
472
  relationship_score = relationships.get(sender_id, 50)
283
473
 
284
474
  # Decision prompt
@@ -286,11 +476,12 @@ class SocietyAgent(CitizenAgent):
286
476
  - Received message: "{content}"
287
477
  - Our relationship score: {relationship_score}/100
288
478
  - My profile: {{
289
- "gender": "{await self._memory.get("gender") or ""}",
290
- "education": "{await self._memory.get("education") or ""}",
291
- "personality": "{await self._memory.get("personality") or ""}",
292
- "occupation": "{await self._memory.get("occupation") or ""}"
479
+ "gender": "{await self.memory.status.get("gender") or ""}",
480
+ "education": "{await self.memory.status.get("education") or ""}",
481
+ "personality": "{await self.memory.status.get("personality") or ""}",
482
+ "occupation": "{await self.memory.status.get("occupation") or ""}"
293
483
  }}
484
+ - My current emotion: {await self.memory.status.get("emotion_types")}
294
485
  - Recent chat history: {chat_histories.get(sender_id, "")}
295
486
 
296
487
  Should I respond to this message? Consider:
@@ -300,7 +491,7 @@ class SocietyAgent(CitizenAgent):
300
491
 
301
492
  Answer only YES or NO."""
302
493
 
303
- should_respond = await self._llm_client.atext_request(
494
+ should_respond = await self._llm_client.atext_request( # type:ignore
304
495
  [
305
496
  {
306
497
  "role": "system",
@@ -310,19 +501,20 @@ class SocietyAgent(CitizenAgent):
310
501
  ]
311
502
  )
312
503
 
313
- if should_respond.strip().upper() != "YES":
314
- await self._memory.update("chat_histories", chat_histories)
504
+ if should_respond.strip().upper() != "YES": # type:ignore
505
+ await self.memory.status.update("chat_histories", chat_histories)
315
506
  return ""
316
507
 
317
508
  response_prompt = f"""Based on:
318
509
  - Received message: "{content}"
319
510
  - Our relationship score: {relationship_score}/100
320
511
  - My profile: {{
321
- "gender": "{await self._memory.get("gender") or ""}",
322
- "education": "{await self._memory.get("education") or ""}",
323
- "personality": "{await self._memory.get("personality") or ""}",
324
- "occupation": "{await self._memory.get("occupation") or ""}"
512
+ "gender": "{await self.memory.status.get("gender") or ""}",
513
+ "education": "{await self.memory.status.get("education") or ""}",
514
+ "personality": "{await self.memory.status.get("personality") or ""}",
515
+ "occupation": "{await self.memory.status.get("occupation") or ""}"
325
516
  }}
517
+ - My current emotion: {await self.memory.status.get("emotion_types")}
326
518
  - Recent chat history: {chat_histories.get(sender_id, "")}
327
519
 
328
520
  Generate an appropriate response that:
@@ -333,7 +525,7 @@ class SocietyAgent(CitizenAgent):
333
525
 
334
526
  Response should be ONLY the message text, no explanations."""
335
527
 
336
- response = await self._llm_client.atext_request(
528
+ response = await self.llm.atext_request(
337
529
  [
338
530
  {
339
531
  "role": "system",
@@ -346,7 +538,7 @@ class SocietyAgent(CitizenAgent):
346
538
  if response:
347
539
  # Update chat history with response
348
540
  chat_histories[sender_id] += f",me: {response}"
349
- await self._memory.update("chat_histories", chat_histories)
541
+ await self.memory.status.update("chat_histories", chat_histories)
350
542
 
351
543
  # Send response
352
544
  serialized_response = json.dumps(
@@ -359,7 +551,7 @@ class SocietyAgent(CitizenAgent):
359
551
  await self.send_message_to_agent(sender_id, serialized_response)
360
552
  logger.info("sender_id", sender_id)
361
553
  logger.info("message", serialized_response)
362
- return response
554
+ return response # type:ignore
363
555
 
364
556
  except Exception as e:
365
557
  logger.warning(f"Error in process_agent_chat_response: {str(e)}")
@@ -371,4 +563,10 @@ class SocietyAgent(CitizenAgent):
371
563
  value = float(value)
372
564
  else:
373
565
  value = int(value)
374
- await self.memory.update(key, value)
566
+ description = f"You received a economic message: Your {key} has changed from {await self.memory.status.get(key)} to {value}"
567
+ await self.memory.status.update(key, value)
568
+ await self.memory.stream.add_economic( # type:ignore
569
+ description=description
570
+ )
571
+ if self.enable_cognition:
572
+ await self.mindBlock.cognitionBlock.emotion_update(description)
@@ -6,6 +6,7 @@ import signal
6
6
  _script_dir = os.path.dirname(os.path.abspath(__file__))
7
7
  _parent_dir = os.path.dirname(_script_dir)
8
8
 
9
+
9
10
  def wrapper(bin: str):
10
11
  binary_path = os.path.join(_parent_dir, bin)
11
12
  if not os.path.exists(binary_path):
@@ -21,12 +22,14 @@ def wrapper(bin: str):
21
22
  stdout=sys.stdout,
22
23
  stderr=sys.stderr,
23
24
  )
25
+
24
26
  # register signal handler
25
27
  def signal_handler(sig, frame):
26
28
  if p.poll() is None:
27
29
  p.send_signal(sig)
28
30
  else:
29
31
  sys.exit(p.poll())
32
+
30
33
  signals = [signal.SIGINT, signal.SIGTERM, signal.SIGHUP]
31
34
  for sig in signals:
32
35
  signal.signal(sig, signal_handler)
@@ -40,5 +43,6 @@ def wrapper(bin: str):
40
43
  def pycityagent_sim():
41
44
  wrapper("pycityagent-sim")
42
45
 
46
+
43
47
  def pycityagent_ui():
44
48
  wrapper("pycityagent-ui")
@@ -8,8 +8,6 @@ import pycityproto.city.economy.v2.org_service_pb2 as org_service
8
8
  import pycityproto.city.economy.v2.org_service_pb2_grpc as org_grpc
9
9
  from google.protobuf import descriptor
10
10
 
11
- economyv2.ORG_TYPE_BANK
12
-
13
11
  __all__ = [
14
12
  "EconomyClient",
15
13
  ]
@@ -4,4 +4,10 @@ from .sence.static import LEVEL_ONE_PRE, POI_TYPE_DICT
4
4
  from .sim import AoiService, PersonService
5
5
  from .simulator import Simulator
6
6
 
7
- __all__ = ["Simulator", "POI_TYPE_DICT", "LEVEL_ONE_PRE", "PersonService", "AoiService"]
7
+ __all__ = [
8
+ "Simulator",
9
+ "POI_TYPE_DICT",
10
+ "LEVEL_ONE_PRE",
11
+ "PersonService",
12
+ "AoiService",
13
+ ]