pycityagent 2.0.0a53__cp311-cp311-macosx_11_0_arm64.whl → 2.0.0a55__cp311-cp311-macosx_11_0_arm64.whl

Sign up to get free protection for your applications and to get access to all the features.
@@ -13,7 +13,8 @@ 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
+ from ..metrics import MlflowClient
17
18
  from .agent_base import Agent, AgentType
18
19
 
19
20
  logger = logging.getLogger("pycityagent")
@@ -32,6 +33,7 @@ class CitizenAgent(Agent):
32
33
  memory: Optional[Memory] = None,
33
34
  economy_client: Optional[EconomyClient] = None,
34
35
  messager: Optional[Messager] = None, # type:ignore
36
+ message_interceptor: Optional[MessageInterceptor] = None, # type:ignore
35
37
  avro_file: Optional[dict] = None,
36
38
  ) -> None:
37
39
  super().__init__(
@@ -40,10 +42,12 @@ class CitizenAgent(Agent):
40
42
  llm_client=llm_client,
41
43
  economy_client=economy_client,
42
44
  messager=messager,
45
+ message_interceptor=message_interceptor,
43
46
  simulator=simulator,
44
47
  memory=memory,
45
48
  avro_file=avro_file,
46
49
  )
50
+ self._mlflow_client = None
47
51
 
48
52
  async def bind_to_simulator(self):
49
53
  await self._bind_to_simulator()
@@ -78,9 +82,7 @@ class CitizenAgent(Agent):
78
82
  dict_person[_key] = _value
79
83
  except KeyError as e:
80
84
  continue
81
- resp = await simulator.add_person(
82
- dict2pb(dict_person, person_pb2.Person())
83
- )
85
+ resp = await simulator.add_person(dict2pb(dict_person, person_pb2.Person()))
84
86
  person_id = resp["person_id"]
85
87
  await status.update("id", person_id, protect_llm_read_only_fields=False)
86
88
  logger.debug(f"Binding to Person `{person_id}` just added to Simulator")
@@ -123,6 +125,21 @@ class CitizenAgent(Agent):
123
125
  }
124
126
  await self._send_message(sender_id, payload, "gather")
125
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
+
126
143
 
127
144
  class InstitutionAgent(Agent):
128
145
  """
@@ -137,6 +154,7 @@ class InstitutionAgent(Agent):
137
154
  memory: Optional[Memory] = None,
138
155
  economy_client: Optional[EconomyClient] = None,
139
156
  messager: Optional[Messager] = None, # type:ignore
157
+ message_interceptor: Optional[MessageInterceptor] = None, # type:ignore
140
158
  avro_file: Optional[dict] = None,
141
159
  ) -> None:
142
160
  super().__init__(
@@ -145,10 +163,12 @@ class InstitutionAgent(Agent):
145
163
  llm_client=llm_client,
146
164
  economy_client=economy_client,
147
165
  messager=messager,
166
+ message_interceptor=message_interceptor,
148
167
  simulator=simulator,
149
168
  memory=memory,
150
169
  avro_file=avro_file,
151
170
  )
171
+ self._mlflow_client = None
152
172
  # 添加响应收集器
153
173
  self._gather_responses: dict[str, asyncio.Future] = {}
154
174
 
@@ -308,3 +328,18 @@ class InstitutionAgent(Agent):
308
328
  # 清理Future
309
329
  for key in futures:
310
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
@@ -56,7 +55,8 @@ class Agent(ABC):
56
55
  type: AgentType = AgentType.Unspecified,
57
56
  llm_client: Optional[LLM] = None,
58
57
  economy_client: Optional[EconomyClient] = None,
59
- messager: Optional[Messager] = None, # type:ignore
58
+ messager: Optional[ray.ObjectRef] = None,
59
+ message_interceptor: Optional[ray.ObjectRef] = None,
60
60
  simulator: Optional[Simulator] = None,
61
61
  memory: Optional[Memory] = None,
62
62
  avro_file: Optional[dict[str, str]] = None,
@@ -82,6 +82,7 @@ class Agent(ABC):
82
82
  self._llm_client = llm_client
83
83
  self._economy_client = economy_client
84
84
  self._messager = messager
85
+ self._message_interceptor = message_interceptor
85
86
  self._simulator = simulator
86
87
  self._memory = memory
87
88
  self._exp_id = -1
@@ -102,12 +103,12 @@ class Agent(ABC):
102
103
  return state
103
104
 
104
105
  @classmethod
105
- def export_class_config(cls) -> Dict[str, Dict]:
106
+ def export_class_config(cls) -> dict[str, dict]:
106
107
  result = {
107
108
  "agent_name": cls.__name__,
108
109
  "config": {},
109
110
  "description": {},
110
- "blocks": []
111
+ "blocks": [],
111
112
  }
112
113
  config = {
113
114
  field: cls.default_values.get(field, "default_value")
@@ -123,16 +124,18 @@ class Agent(ABC):
123
124
  for attr_name, attr_type in hints.items():
124
125
  if inspect.isclass(attr_type) and issubclass(attr_type, Block):
125
126
  block_config = attr_type.export_class_config()
126
- result["blocks"].append({
127
- "name": attr_name,
128
- "config": block_config[0],
129
- "description": block_config[1],
130
- "children": cls._export_subblocks(attr_type)
131
- })
127
+ result["blocks"].append(
128
+ {
129
+ "name": attr_name,
130
+ "config": block_config[0], # type:ignore
131
+ "description": block_config[1], # type:ignore
132
+ "children": cls._export_subblocks(attr_type),
133
+ }
134
+ )
132
135
  return result
133
136
 
134
137
  @classmethod
135
- def _export_subblocks(cls, block_cls: type[Block]) -> list[Dict]:
138
+ def _export_subblocks(cls, block_cls: type[Block]) -> list[dict]:
136
139
  children = []
137
140
  hints = get_type_hints(block_cls) # 获取类的注解
138
141
  for attr_name, attr_type in hints.items():
@@ -141,8 +144,8 @@ class Agent(ABC):
141
144
  children.append(
142
145
  {
143
146
  "name": attr_name,
144
- "config": block_config[0],
145
- "description": block_config[1],
147
+ "config": block_config[0], # type:ignore
148
+ "description": block_config[1], # type:ignore
146
149
  "children": cls._export_subblocks(attr_type),
147
150
  }
148
151
  )
@@ -253,6 +256,12 @@ class Agent(ABC):
253
256
  """
254
257
  self._pgsql_writer = pgsql_writer
255
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
+
256
265
  @property
257
266
  def uuid(self):
258
267
  """The Agent's UUID"""
@@ -289,24 +298,24 @@ class Agent(ABC):
289
298
  f"Memory access before assignment, please `set_memory` first!"
290
299
  )
291
300
  return self._memory
292
-
301
+
293
302
  @property
294
303
  def status(self):
295
304
  """The Agent's Status Memory"""
296
- if self._memory.status is None:
305
+ if self.memory.status is None:
297
306
  raise RuntimeError(
298
307
  f"Status access before assignment, please `set_memory` first!"
299
308
  )
300
- return self._memory.status
301
-
309
+ return self.memory.status
310
+
302
311
  @property
303
312
  def stream(self):
304
313
  """The Agent's Stream Memory"""
305
- if self._memory.stream is None:
314
+ if self.memory.stream is None:
306
315
  raise RuntimeError(
307
316
  f"Stream access before assignment, please `set_memory` first!"
308
317
  )
309
- return self._memory.stream
318
+ return self.memory.stream
310
319
 
311
320
  @property
312
321
  def simulator(self):
@@ -335,7 +344,7 @@ class Agent(ABC):
335
344
  async def messager_ping(self):
336
345
  if self._messager is None:
337
346
  raise RuntimeError("Messager is not set")
338
- return await self._messager.ping()
347
+ return await self._messager.ping.remote() # type:ignore
339
348
 
340
349
  async def generate_user_survey_response(self, survey: dict) -> str:
341
350
  """生成回答 —— 可重写
@@ -421,7 +430,7 @@ class Agent(ABC):
421
430
  _data_tuples
422
431
  )
423
432
  )
424
- await self.messager.send_message.remote(f"exps/{self._exp_id}/user_payback", {"count": 1})
433
+ await self.messager.send_message.remote(f"exps/{self._exp_id}/user_payback", {"count": 1})# type:ignore
425
434
 
426
435
  async def generate_user_chat_response(self, question: str) -> str:
427
436
  """生成回答 —— 可重写
@@ -508,7 +517,7 @@ class Agent(ABC):
508
517
  _data
509
518
  )
510
519
  )
511
- await self.messager.send_message.remote(f"exps/{self._exp_id}/user_payback", {"count": 1})
520
+ await self.messager.send_message.remote(f"exps/{self._exp_id}/user_payback", {"count": 1})# type:ignore
512
521
  print(f"Sent payback message to {self._exp_id}")
513
522
 
514
523
  async def process_agent_chat_response(self, payload: dict) -> str:
@@ -579,7 +588,12 @@ class Agent(ABC):
579
588
  if self._messager is None:
580
589
  raise RuntimeError("Messager is not set")
581
590
  topic = f"exps/{self._exp_id}/agents/{to_agent_uuid}/{sub_topic}"
582
- 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
+ )
583
597
 
584
598
  async def send_message_to_agent(
585
599
  self, to_agent_uuid: str, content: str, type: str = "social"
@@ -643,6 +657,6 @@ class Agent(ABC):
643
657
  当_blocked为True时,不执行forward方法
644
658
  """
645
659
  if self._messager is not None:
646
- await self._messager.ping.remote()
660
+ await self._messager.ping.remote() # type:ignore
647
661
  if not self._blocked:
648
662
  await self.forward()
@@ -294,4 +294,4 @@ Execution Steps: \n{formated_steps}
294
294
  def clean_json_response(self, response: str) -> str:
295
295
  """Clean special characters in LLM response"""
296
296
  response = response.replace('```json', '').replace('```', '')
297
- return response.strip()
297
+ return response.strip()
@@ -0,0 +1,99 @@
1
+ import asyncio
2
+
3
+ from pycityagent.llm import LLM
4
+ from pycityagent.message import MessageBlockBase, MessageBlockListenerBase
5
+
6
+
7
+ async def check_message(
8
+ from_uuid: str, to_uuid: str, llm_client: LLM, content: str
9
+ ) -> bool:
10
+ """
11
+ 使用LLM检查消息是否合规
12
+ 返回: (是否合规, from_uuid, to_uuid)
13
+ """
14
+ print(f"\n检查消息: {from_uuid} -> {to_uuid}: {content}")
15
+
16
+ prompt = f"""
17
+ 请判断以下消息是否具有情绪煽动性:
18
+ 发送者ID: {from_uuid}
19
+ 接收者ID: {to_uuid}
20
+ 消息内容: {content}
21
+
22
+ 如果消息具有情绪煽动性,请返回 False;如果消息正常,请返回 True。
23
+ """
24
+
25
+ if "test" in content.lower():
26
+ is_valid = False
27
+ else:
28
+ is_valid = True
29
+ print(f"消息检查结果: {'合规' if is_valid else '不合规'}")
30
+ return is_valid
31
+
32
+
33
+ class EdgeMessageBlock(MessageBlockBase):
34
+ async def forward( # type:ignore
35
+ self,
36
+ from_uuid: str,
37
+ to_uuid: str,
38
+ msg: str,
39
+ black_list: list[tuple[str, str]],
40
+ ):
41
+ if (from_uuid, to_uuid) in set(black_list):
42
+ # 可选同时返回入队的信息(False,err) 如果只返回bool值则默认报错信息入队
43
+ return False
44
+ else:
45
+ is_valid = await check_message(
46
+ from_uuid=from_uuid,
47
+ to_uuid=to_uuid,
48
+ llm_client=self.llm,
49
+ content=msg,
50
+ )
51
+ if not is_valid:
52
+ # 直接添加即可 在框架内部的异步锁保证不会冲突
53
+ black_list.append((from_uuid, to_uuid))
54
+ return is_valid
55
+
56
+
57
+ class PointMessageBlock(MessageBlockBase):
58
+ async def forward( # type:ignore
59
+ self,
60
+ from_uuid: str,
61
+ to_uuid: str,
62
+ msg: str,
63
+ violation_counts: dict[str, int],
64
+ black_list: list[tuple[str, str]],
65
+ ):
66
+ if (from_uuid, to_uuid) in set(black_list):
67
+ # 可选同时返回入队的信息(False,err) 如果只返回bool值则默认报错信息入队
68
+ return False
69
+ else:
70
+ # violation count在框架内自动维护 这里不用管
71
+ is_valid = await check_message(
72
+ from_uuid=from_uuid,
73
+ to_uuid=to_uuid,
74
+ llm_client=self.llm,
75
+ content=msg,
76
+ )
77
+ if not is_valid and violation_counts[from_uuid] >= 3 - 1:
78
+ # 直接添加即可 在框架内部的异步锁保证不会冲突
79
+ black_list.append((from_uuid, to_uuid))
80
+ return is_valid
81
+
82
+
83
+ class MessageBlockListener(MessageBlockListenerBase):
84
+ def __init__(
85
+ self, save_queue_values: bool = False, get_queue_period: float = 0.1
86
+ ) -> None:
87
+ super().__init__(save_queue_values, get_queue_period)
88
+
89
+ async def forward(
90
+ self,
91
+ ):
92
+ while True:
93
+ if self.has_queue:
94
+ value = await self.queue.get_async() # type: ignore
95
+ if self._save_queue_values:
96
+ self._values_from_queue.append(value)
97
+ print(f"get `{value}` from queue")
98
+ # do something with the value
99
+ await asyncio.sleep(self._get_queue_period)
@@ -8,8 +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.workflow import Block
12
11
  from pycityagent.tools import UpdateWithSimulator
12
+ from pycityagent.workflow import Block
13
13
 
14
14
  from .blocks import (CognitionBlock, EconomyBlock, MobilityBlock, NeedsBlock,
15
15
  OtherBlock, PlanBlock, SocialBlock)
@@ -54,7 +54,6 @@ class PlanAndActionBlock(Block):
54
54
  llm=llm, memory=memory, simulator=simulator, economy_client=economy_client
55
55
  )
56
56
  self.otherBlock = OtherBlock(llm=llm, memory=memory)
57
-
58
57
  async def plan_generation(self):
59
58
  """Generate plan"""
60
59
  current_plan = await self.memory.status.get("current_plan")
@@ -79,45 +78,43 @@ class PlanAndActionBlock(Block):
79
78
  )
80
79
  result = None
81
80
  if step_type == "mobility":
82
- if self.enable_mobility:
81
+ if self.enable_mobility: # type:ignore
83
82
  result = await self.mobilityBlock.forward(
84
83
  current_step, execution_context
85
84
  )
86
85
  else:
87
86
  result = {
88
- 'success': False,
89
- 'evaluation': f'Mobility Behavior is disabled',
90
- 'consumed_time': 0,
91
- 'node_id': None
87
+ "success": False,
88
+ "evaluation": f"Mobility Behavior is disabled",
89
+ "consumed_time": 0,
90
+ "node_id": None,
92
91
  }
93
92
  elif step_type == "social":
94
- if self.enable_social:
93
+ if self.enable_social: # type:ignore
95
94
  result = await self.socialBlock.forward(
96
95
  current_step, execution_context
97
96
  )
98
97
  else:
99
98
  result = {
100
- 'success': False,
101
- 'evaluation': f'Social Behavior is disabled',
102
- 'consumed_time': 0,
103
- 'node_id': None
99
+ "success": False,
100
+ "evaluation": f"Social Behavior is disabled",
101
+ "consumed_time": 0,
102
+ "node_id": None,
104
103
  }
105
104
  elif step_type == "economy":
106
- if self.enable_economy:
105
+ if self.enable_economy: # type:ignore
107
106
  result = await self.economyBlock.forward(
108
107
  current_step, execution_context
109
108
  )
110
109
  else:
111
110
  result = {
112
- 'success': False,
113
- 'evaluation': f'Economy Behavior is disabled',
114
- 'consumed_time': 0,
115
- 'node_id': None
111
+ "success": False,
112
+ "evaluation": f"Economy Behavior is disabled",
113
+ "consumed_time": 0,
114
+ "node_id": None,
116
115
  }
117
116
  elif step_type == "other":
118
- result = await self.otherBlock.forward(
119
- current_step, execution_context
120
- )
117
+ result = await self.otherBlock.forward(current_step, execution_context)
121
118
  if result != None:
122
119
  logger.info(f"Execution result: {result}")
123
120
  current_step["evaluation"] = result
@@ -156,7 +153,9 @@ class MindBlock(Block):
156
153
 
157
154
  def __init__(self, llm: LLM, memory: Memory, simulator: Simulator):
158
155
  super().__init__(name="mind_block", llm=llm, memory=memory, simulator=simulator)
159
- self.cognitionBlock = CognitionBlock(llm=self.llm, memory=self.memory, simulator=simulator)
156
+ self.cognitionBlock = CognitionBlock(
157
+ llm=self.llm, memory=self.memory, simulator=simulator
158
+ )
160
159
 
161
160
  async def forward(self):
162
161
  await self.cognitionBlock.forward()
@@ -165,7 +164,12 @@ class SocietyAgent(CitizenAgent):
165
164
  mindBlock: MindBlock
166
165
  planAndActionBlock: PlanAndActionBlock
167
166
  update_with_sim = UpdateWithSimulator()
168
- configurable_fields = ["enable_cognition", "enable_mobility", "enable_social", "enable_economy"]
167
+ configurable_fields = [
168
+ "enable_cognition",
169
+ "enable_mobility",
170
+ "enable_social",
171
+ "enable_economy",
172
+ ]
169
173
  default_values = {
170
174
  "enable_cognition": True,
171
175
  "enable_mobility": True,
@@ -195,14 +199,14 @@ class SocietyAgent(CitizenAgent):
195
199
  economy_client=economy_client,
196
200
  )
197
201
  self.mindBlock = MindBlock(
198
- llm=self._llm_client, memory=self.memory, simulator=self._simulator
202
+ llm=self.llm, memory=self.memory, simulator=self.simulator
199
203
  )
200
204
  self.planAndActionBlock = PlanAndActionBlock(
201
205
  agent=self,
202
- llm=self._llm_client,
206
+ llm=self.llm,
203
207
  memory=self.memory,
204
- simulator=self._simulator,
205
- economy_client=self._economy_client,
208
+ simulator=self.simulator,
209
+ economy_client=self.economy_client,
206
210
  )
207
211
  self.step_count = -1
208
212
  self.cognition_update = -1
@@ -305,7 +309,114 @@ class SocietyAgent(CitizenAgent):
305
309
  # The previous step has not been completed
306
310
  return False
307
311
 
308
- async def process_agent_chat_response(self, payload: dict) -> str:
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
309
420
  if payload["type"] == "social":
310
421
  resp = f"Agent {self._uuid} received agent chat response: {payload}"
311
422
  logger.info(resp)
@@ -380,7 +491,7 @@ class SocietyAgent(CitizenAgent):
380
491
 
381
492
  Answer only YES or NO."""
382
493
 
383
- should_respond = await self._llm_client.atext_request(
494
+ should_respond = await self._llm_client.atext_request( # type:ignore
384
495
  [
385
496
  {
386
497
  "role": "system",
@@ -390,7 +501,7 @@ class SocietyAgent(CitizenAgent):
390
501
  ]
391
502
  )
392
503
 
393
- if should_respond.strip().upper() != "YES":
504
+ if should_respond.strip().upper() != "YES": # type:ignore
394
505
  await self.memory.status.update("chat_histories", chat_histories)
395
506
  return ""
396
507
 
@@ -414,7 +525,7 @@ class SocietyAgent(CitizenAgent):
414
525
 
415
526
  Response should be ONLY the message text, no explanations."""
416
527
 
417
- response = await self._llm_client.atext_request(
528
+ response = await self.llm.atext_request(
418
529
  [
419
530
  {
420
531
  "role": "system",
@@ -440,7 +551,7 @@ class SocietyAgent(CitizenAgent):
440
551
  await self.send_message_to_agent(sender_id, serialized_response)
441
552
  logger.info("sender_id", sender_id)
442
553
  logger.info("message", serialized_response)
443
- return response
554
+ return response # type:ignore
444
555
 
445
556
  except Exception as e:
446
557
  logger.warning(f"Error in process_agent_chat_response: {str(e)}")
@@ -454,6 +565,8 @@ class SocietyAgent(CitizenAgent):
454
565
  value = int(value)
455
566
  description = f"You received a economic message: Your {key} has changed from {await self.memory.status.get(key)} to {value}"
456
567
  await self.memory.status.update(key, value)
457
- await self.memory.stream.add_economic(description=description)
568
+ await self.memory.stream.add_economic( # type:ignore
569
+ description=description
570
+ )
458
571
  if self.enable_cognition:
459
572
  await self.mindBlock.cognitionBlock.emotion_update(description)