pycityagent 2.0.0a65__cp311-cp311-macosx_11_0_arm64.whl → 2.0.0a67__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.
Files changed (87) hide show
  1. pycityagent/agent/agent.py +157 -57
  2. pycityagent/agent/agent_base.py +316 -43
  3. pycityagent/cityagent/bankagent.py +49 -9
  4. pycityagent/cityagent/blocks/__init__.py +1 -2
  5. pycityagent/cityagent/blocks/cognition_block.py +54 -31
  6. pycityagent/cityagent/blocks/dispatcher.py +22 -17
  7. pycityagent/cityagent/blocks/economy_block.py +46 -32
  8. pycityagent/cityagent/blocks/mobility_block.py +209 -105
  9. pycityagent/cityagent/blocks/needs_block.py +101 -54
  10. pycityagent/cityagent/blocks/other_block.py +42 -33
  11. pycityagent/cityagent/blocks/plan_block.py +59 -42
  12. pycityagent/cityagent/blocks/social_block.py +167 -126
  13. pycityagent/cityagent/blocks/utils.py +13 -6
  14. pycityagent/cityagent/firmagent.py +17 -35
  15. pycityagent/cityagent/governmentagent.py +3 -3
  16. pycityagent/cityagent/initial.py +79 -49
  17. pycityagent/cityagent/memory_config.py +123 -94
  18. pycityagent/cityagent/message_intercept.py +0 -4
  19. pycityagent/cityagent/metrics.py +41 -0
  20. pycityagent/cityagent/nbsagent.py +24 -36
  21. pycityagent/cityagent/societyagent.py +9 -4
  22. pycityagent/cli/wrapper.py +2 -2
  23. pycityagent/economy/econ_client.py +407 -81
  24. pycityagent/environment/__init__.py +0 -3
  25. pycityagent/environment/sim/__init__.py +0 -3
  26. pycityagent/environment/sim/aoi_service.py +2 -2
  27. pycityagent/environment/sim/client.py +3 -31
  28. pycityagent/environment/sim/clock_service.py +2 -2
  29. pycityagent/environment/sim/lane_service.py +8 -8
  30. pycityagent/environment/sim/light_service.py +8 -8
  31. pycityagent/environment/sim/pause_service.py +9 -10
  32. pycityagent/environment/sim/person_service.py +20 -20
  33. pycityagent/environment/sim/road_service.py +2 -2
  34. pycityagent/environment/sim/sim_env.py +21 -5
  35. pycityagent/environment/sim/social_service.py +4 -4
  36. pycityagent/environment/simulator.py +249 -27
  37. pycityagent/environment/utils/__init__.py +2 -2
  38. pycityagent/environment/utils/geojson.py +2 -2
  39. pycityagent/environment/utils/grpc.py +4 -4
  40. pycityagent/environment/utils/map_utils.py +2 -2
  41. pycityagent/llm/embeddings.py +147 -28
  42. pycityagent/llm/llm.py +178 -111
  43. pycityagent/llm/llmconfig.py +5 -0
  44. pycityagent/llm/utils.py +4 -0
  45. pycityagent/memory/__init__.py +0 -4
  46. pycityagent/memory/const.py +2 -2
  47. pycityagent/memory/faiss_query.py +140 -61
  48. pycityagent/memory/memory.py +394 -91
  49. pycityagent/memory/memory_base.py +140 -34
  50. pycityagent/memory/profile.py +13 -13
  51. pycityagent/memory/self_define.py +13 -13
  52. pycityagent/memory/state.py +14 -14
  53. pycityagent/message/message_interceptor.py +253 -3
  54. pycityagent/message/messager.py +133 -6
  55. pycityagent/metrics/mlflow_client.py +47 -4
  56. pycityagent/pycityagent-sim +0 -0
  57. pycityagent/pycityagent-ui +0 -0
  58. pycityagent/simulation/__init__.py +3 -2
  59. pycityagent/simulation/agentgroup.py +150 -54
  60. pycityagent/simulation/simulation.py +276 -66
  61. pycityagent/survey/manager.py +45 -3
  62. pycityagent/survey/models.py +42 -2
  63. pycityagent/tools/__init__.py +1 -2
  64. pycityagent/tools/tool.py +93 -69
  65. pycityagent/utils/avro_schema.py +2 -2
  66. pycityagent/utils/parsers/code_block_parser.py +1 -1
  67. pycityagent/utils/parsers/json_parser.py +2 -2
  68. pycityagent/utils/parsers/parser_base.py +2 -2
  69. pycityagent/workflow/block.py +64 -13
  70. pycityagent/workflow/prompt.py +31 -23
  71. pycityagent/workflow/trigger.py +91 -24
  72. {pycityagent-2.0.0a65.dist-info → pycityagent-2.0.0a67.dist-info}/METADATA +2 -2
  73. pycityagent-2.0.0a67.dist-info/RECORD +97 -0
  74. pycityagent/environment/interact/__init__.py +0 -0
  75. pycityagent/environment/interact/interact.py +0 -198
  76. pycityagent/environment/message/__init__.py +0 -0
  77. pycityagent/environment/sence/__init__.py +0 -0
  78. pycityagent/environment/sence/static.py +0 -416
  79. pycityagent/environment/sidecar/__init__.py +0 -8
  80. pycityagent/environment/sidecar/sidecarv2.py +0 -109
  81. pycityagent/environment/sim/economy_services.py +0 -192
  82. pycityagent/metrics/utils/const.py +0 -0
  83. pycityagent-2.0.0a65.dist-info/RECORD +0 -105
  84. {pycityagent-2.0.0a65.dist-info → pycityagent-2.0.0a67.dist-info}/LICENSE +0 -0
  85. {pycityagent-2.0.0a65.dist-info → pycityagent-2.0.0a67.dist-info}/WHEEL +0 -0
  86. {pycityagent-2.0.0a65.dist-info → pycityagent-2.0.0a67.dist-info}/entry_points.txt +0 -0
  87. {pycityagent-2.0.0a65.dist-info → pycityagent-2.0.0a67.dist-info}/top_level.txt +0 -0
@@ -1,27 +1,31 @@
1
+ import json
2
+ import logging
3
+
4
+ from pycityagent.environment.simulator import Simulator
1
5
  from pycityagent.llm import LLM
2
- from pycityagent.workflow.block import Block
3
6
  from pycityagent.memory import Memory
4
- from pycityagent.environment.simulator import Simulator
7
+ from pycityagent.workflow.block import Block
5
8
  from pycityagent.workflow.prompt import FormatPrompt
6
- import json
7
- import logging
9
+
8
10
  logger = logging.getLogger("pycityagent")
9
11
 
12
+
10
13
  def extract_json(output_str):
11
14
  try:
12
15
  # Find the positions of the first '{' and the last '}'
13
- start = output_str.find('{')
14
- end = output_str.rfind('}')
15
-
16
+ start = output_str.find("{")
17
+ end = output_str.rfind("}")
18
+
16
19
  # Extract the substring containing the JSON
17
- json_str = output_str[start:end+1]
18
-
20
+ json_str = output_str[start : end + 1]
21
+
19
22
  # Convert the JSON string to a dictionary
20
23
  return json_str
21
24
  except (ValueError, json.JSONDecodeError) as e:
22
25
  logger.warning(f"Failed to extract JSON: {e}")
23
26
  return None
24
27
 
28
+
25
29
  class CognitionBlock(Block):
26
30
  configurable_fields = ["top_k"]
27
31
  default_values = {"top_k": 20}
@@ -32,12 +36,12 @@ class CognitionBlock(Block):
32
36
  def __init__(self, llm: LLM, memory: Memory, simulator: Simulator):
33
37
  super().__init__("CognitionBlock", llm=llm, memory=memory, simulator=simulator)
34
38
  self.top_k = 20
35
-
39
+
36
40
  async def set_status(self, status):
37
41
  for key in status:
38
42
  await self.memory.status.update(key, status[key])
39
43
  return
40
-
44
+
41
45
  async def attitude_update(self):
42
46
  """Cognition - attitude update workflow"""
43
47
  attitude = await self.memory.status.get("attitude")
@@ -56,7 +60,7 @@ class CognitionBlock(Block):
56
60
  "income": await self.memory.status.get("income"),
57
61
  "skill": await self.memory.status.get("skill"),
58
62
  "thought": await self.memory.status.get("thought"),
59
- "emotion_types": await self.memory.status.get("emotion_types")
63
+ "emotion_types": await self.memory.status.get("emotion_types"),
60
64
  }
61
65
  for topic in attitude:
62
66
  description_prompt = """
@@ -82,7 +86,7 @@ class CognitionBlock(Block):
82
86
  f"You need to decide your attitude towards topic: {topic}, "
83
87
  f"which you previously rated your attitude towards this topic as: {previous_attitude} "
84
88
  "(0 meaning oppose, 10 meaning support). "
85
- "Please return a new attitude rating (0-10, smaller meaning oppose, larger meaning support) in JSON format, and explain, e.g. {{\"attitude\": 5}}"
89
+ 'Please return a new attitude rating (0-10, smaller meaning oppose, larger meaning support) in JSON format, and explain, e.g. {{"attitude": 5}}'
86
90
  )
87
91
  question_prompt = description_prompt + incident_prompt + problem_prompt
88
92
  question_prompt = FormatPrompt(question_prompt)
@@ -99,22 +103,25 @@ class CognitionBlock(Block):
99
103
  prompt_data["disgust"] = disgust
100
104
  prompt_data["anger"] = anger
101
105
  prompt_data["surprise"] = surprise
102
-
106
+
103
107
  question_prompt.format(**prompt_data)
104
108
  evaluation = True
109
+ response: dict = {}
105
110
  for retry in range(10):
106
111
  try:
107
- response = await self.llm.atext_request(question_prompt.to_dialog(), timeout=300)
108
- response = json.loads(extract_json(response))
112
+ _response = await self.llm.atext_request(
113
+ question_prompt.to_dialog(), timeout=300
114
+ )
115
+ response = json.loads(extract_json(_response)) # type:ignore
109
116
  evaluation = False
110
117
  break
111
118
  except:
112
119
  pass
113
120
  if evaluation:
114
- raise f"Request for attitude:{topic} update failed"
121
+ raise Exception(f"Request for attitude:{topic} update failed")
115
122
  attitude[topic] = response["attitude"]
116
123
  await self.memory.status.update("attitude", attitude)
117
-
124
+
118
125
  async def thought_update(self):
119
126
  """Cognition - thought update workflow"""
120
127
  description_prompt = """
@@ -171,33 +178,36 @@ class CognitionBlock(Block):
171
178
  surprise=surprise,
172
179
  emotion=await self.memory.status.get("emotion"),
173
180
  thought=await self.memory.status.get("thought"),
174
- emotion_types=await self.memory.status.get("emotion_types")
181
+ emotion_types=await self.memory.status.get("emotion_types"),
175
182
  )
176
-
183
+
177
184
  evaluation = True
185
+ response: dict = {}
178
186
  for retry in range(10):
179
187
  try:
180
- response = await self.llm.atext_request(question_prompt.to_dialog(), timeout=300)
181
- response = json.loads(extract_json(response))
188
+ _response = await self.llm.atext_request(
189
+ question_prompt.to_dialog(), timeout=300
190
+ )
191
+ response = json.loads(extract_json(_response)) # type:ignore
182
192
  evaluation = False
183
193
  break
184
194
  except:
185
195
  pass
186
196
  if evaluation:
187
197
  raise Exception("Request for cognition update failed")
188
-
198
+
189
199
  thought = str(response["thought"])
190
200
  await self.memory.status.update("thought", thought)
191
201
  await self.memory.stream.add_cognition(description=thought)
192
202
  return
193
-
203
+
194
204
  async def end_of_day(self):
195
205
  """Cognition - end of day workflow"""
196
206
  time = await self.simulator.get_simulator_second_from_start_of_day()
197
207
  if time >= 86400 - 10 * 60:
198
208
  return True
199
209
  return False
200
-
210
+
201
211
  async def forward(self):
202
212
  """Cognition workflow: Daily update"""
203
213
  # cognition update: thought and attitude
@@ -220,7 +230,7 @@ class CognitionBlock(Block):
220
230
  Joy, Distress, Resentment, Pity, Hope, Fear, Satisfaction, Relief, Disappointment, Pride, Admiration, Shame, Reproach, Liking, Disliking, Gratitude, Anger, Gratification, Remorse, Love, Hate.
221
231
  """
222
232
 
223
- incident_prompt = f"{incident}" #waiting for incident port
233
+ incident_prompt = f"{incident}" # waiting for incident port
224
234
  question_prompt = """
225
235
  Please reconsider your emotion intensities:
226
236
  sadness, joy, fear, disgust, anger, surprise (0 meaning not at all, 10 meaning very much).
@@ -256,14 +266,17 @@ class CognitionBlock(Block):
256
266
  surprise=surprise,
257
267
  emotion=await self.memory.status.get("emotion"),
258
268
  thought=await self.memory.status.get("thought"),
259
- emotion_types=await self.memory.status.get("emotion_types")
269
+ emotion_types=await self.memory.status.get("emotion_types"),
260
270
  )
261
-
271
+
262
272
  evaluation = True
273
+ response: dict = {}
263
274
  for retry in range(10):
264
275
  try:
265
- response = await self.llm.atext_request(question_prompt.to_dialog(), timeout=300)
266
- response = json.loads(extract_json(response))
276
+ _response = await self.llm.atext_request(
277
+ question_prompt.to_dialog(), timeout=300
278
+ )
279
+ response = json.loads(extract_json(_response)) # type:ignore
267
280
  evaluation = False
268
281
  break
269
282
  except Exception as e:
@@ -272,6 +285,16 @@ class CognitionBlock(Block):
272
285
  if evaluation:
273
286
  raise Exception("Request for cognition update failed")
274
287
 
275
- await self.memory.status.update("emotion", {"sadness": int(response["sadness"]), "joy": int(response["joy"]), "fear": int(response["fear"]), "disgust": int(response["disgust"]), "anger": int(response["anger"]), "surprise": int(response["surprise"])})
288
+ await self.memory.status.update(
289
+ "emotion",
290
+ {
291
+ "sadness": int(response["sadness"]),
292
+ "joy": int(response["joy"]),
293
+ "fear": int(response["fear"]),
294
+ "disgust": int(response["disgust"]),
295
+ "anger": int(response["anger"]),
296
+ "surprise": int(response["surprise"]),
297
+ },
298
+ )
276
299
  await self.memory.status.update("emotion_types", str(response["word"]))
277
300
  return response["conclusion"]
@@ -1,9 +1,11 @@
1
+ import logging
1
2
  import random
2
3
  from typing import Dict, List
4
+
3
5
  from pycityagent.llm.llm import LLM
4
6
  from pycityagent.workflow.block import Block
5
7
  from pycityagent.workflow.prompt import FormatPrompt
6
- import logging
8
+
7
9
  logger = logging.getLogger("pycityagent")
8
10
 
9
11
  DISPATCHER_PROMPT = """
@@ -14,18 +16,19 @@ Step information:
14
16
  {step}
15
17
  """
16
18
 
19
+
17
20
  class BlockDispatcher:
18
21
  def __init__(self, llm: LLM):
19
22
  self.llm = llm
20
23
  self.blocks: Dict[str, Block] = {}
21
24
  self.prompt = FormatPrompt(DISPATCHER_PROMPT)
22
-
25
+
23
26
  def register_blocks(self, blocks: List[Block]) -> None:
24
27
  """Register multiple blocks at once"""
25
28
  for block in blocks:
26
29
  block_name = block.__class__.__name__.lower()
27
30
  self.blocks[block_name] = block
28
-
31
+
29
32
  def _get_function_schema(self) -> dict:
30
33
  """Generate function schema for LLM function call"""
31
34
  # 创建 block 选项说明
@@ -33,7 +36,7 @@ class BlockDispatcher:
33
36
  name: block.description # type: ignore
34
37
  for name, block in self.blocks.items()
35
38
  }
36
-
39
+
37
40
  return {
38
41
  "type": "function",
39
42
  "function": {
@@ -45,34 +48,36 @@ class BlockDispatcher:
45
48
  "block_name": {
46
49
  "type": "string",
47
50
  "enum": list(self.blocks.keys()),
48
- "description": f"Available blocks and their descriptions: {block_descriptions}"
51
+ "description": f"Available blocks and their descriptions: {block_descriptions}",
49
52
  }
50
53
  },
51
- "required": ["block_name"]
52
- }
53
- }
54
+ "required": ["block_name"],
55
+ },
56
+ },
54
57
  }
55
-
58
+
56
59
  async def dispatch(self, step: dict) -> Block:
57
60
  """Dispatch the step to appropriate block based on LLM function call"""
58
61
  try:
59
62
  function_schema = self._get_function_schema()
60
63
  self.prompt.format(step=step)
61
-
64
+
62
65
  # Call LLM with tools schema
63
66
  function_args = await self.llm.atext_request(
64
67
  self.prompt.to_dialog(),
65
68
  tools=[function_schema],
66
- tool_choice={"type": "function", "function": {"name": "select_block"}}
69
+ tool_choice={"type": "function", "function": {"name": "select_block"}},
67
70
  )
68
-
69
- selected_block = function_args.get("block_name") # type: ignore
70
-
71
+
72
+ selected_block = function_args.get("block_name") # type: ignore
73
+
71
74
  if selected_block not in self.blocks:
72
- raise ValueError(f"Selected block '{selected_block}' not found in registered blocks")
73
-
75
+ raise ValueError(
76
+ f"Selected block '{selected_block}' not found in registered blocks"
77
+ )
78
+
74
79
  return self.blocks[selected_block]
75
-
80
+
76
81
  except Exception as e:
77
82
  logger.warning(f"Failed to dispatch block: {e}")
78
83
  return random.choice(list(self.blocks.values()))
@@ -3,6 +3,7 @@ import random
3
3
  from pycityagent.llm.llm import LLM
4
4
  from pycityagent.workflow.block import Block
5
5
  from pycityagent.memory import Memory
6
+ import pycityproto.city.economy.v2.economy_pb2 as economyv2
6
7
 
7
8
  from .utils import clean_json_response, TIME_ESTIMATE_PROMPT
8
9
 
@@ -21,6 +22,15 @@ from pycityagent.workflow import Block
21
22
  from pycityagent.economy import EconomyClient
22
23
  from .utils import *
23
24
  import numbers
25
+ import numpy as np
26
+ import asyncio
27
+
28
+ def softmax(x, gamma=1.0):
29
+ if not isinstance(x, np.ndarray):
30
+ x = np.array(x)
31
+ x *= gamma
32
+ e_x = np.exp(x - np.max(x))
33
+ return e_x / e_x.sum(axis=-1, keepdims=True)
24
34
 
25
35
  class WorkBlock(Block):
26
36
  """WorkPlace Block"""
@@ -80,10 +90,10 @@ class ConsumptionBlock(Block):
80
90
  async def forward(self, step, context):
81
91
  self.forward_times += 1
82
92
  agent_id = await self.memory.status.get("id") # agent_id
83
- firm_id = await self.memory.status.get('firm_id')
93
+ firms_id = await self.economy_client.get_org_entity_ids(economyv2.ORG_TYPE_FIRM)
84
94
  intention = step["intention"]
85
95
  month_consumption = await self.memory.status.get('to_consumption_currency')
86
- consumption_currency = await self.memory.status.get('consumption_currency')
96
+ consumption_currency = await self.economy_client.get(agent_id, 'consumption')
87
97
  if consumption_currency >= month_consumption:
88
98
  node_id = await self.memory.stream.add_economy(description=f"I have passed the monthly consumption limit, so I will not consume.")
89
99
  return {
@@ -93,20 +103,20 @@ class ConsumptionBlock(Block):
93
103
  'node_id': node_id
94
104
  }
95
105
  consumption = min(month_consumption/1, month_consumption-consumption_currency)
96
- price = await self.economy_client.get(firm_id, 'price') # agent_id
97
- wealth = await self.economy_client.get(agent_id, 'currency')
98
- this_demand = int(consumption//price)
99
- _, post_consumption_wealth = await self.economy_client.calculate_consumption(firm_id, [agent_id], [this_demand])
100
- post_consumption_wealth = post_consumption_wealth[0]
101
- await self.memory.status.update('consumption_currency', consumption_currency+wealth-post_consumption_wealth)
102
- goods_demand = await self.memory.status.get('goods_demand')
103
- goods_consumption = await self.memory.status.get('goods_consumption')
104
- await self.memory.status.update('goods_demand', goods_demand+this_demand)
105
- await self.memory.status.update('goods_consumption', goods_consumption+int((wealth-post_consumption_wealth)//price))
106
- node_id = await self.memory.stream.add_economy(description=f"I bought some goods, and spent {this_demand} on {intention}")
106
+ prices = []
107
+ for firm_id in firms_id:
108
+ price = await self.economy_client.get(firm_id, 'price')
109
+ prices.append(price)
110
+ consumption_each_firm = consumption*softmax(prices, gamma=-0.01)
111
+ demand_each_firm = []
112
+ for i in range(len(firms_id)):
113
+ demand_each_firm.append(int(consumption_each_firm//prices[i]))
114
+
115
+ real_consumption = await self.economy_client.calculate_consumption(firms_id, agent_id, demand_each_firm)
116
+ node_id = await self.memory.stream.add_economy(description=f"I bought some goods, and spent {real_consumption:.1f} on {intention}")
107
117
  evaluation = {
108
118
  'success': True,
109
- 'evaluation': f"I bought some goods, and spent {this_demand} on {intention}",
119
+ 'evaluation': f"I bought some goods, and spent {real_consumption:.1f} on {intention}",
110
120
  'consumed_time': 20,
111
121
  'node_id': node_id
112
122
  }
@@ -172,16 +182,22 @@ class MonthPlanBlock(Block):
172
182
  async def forward(self):
173
183
  if await self.month_trigger():
174
184
  agent_id = await self.memory.status.get("id")
185
+ firms_id = await self.economy_client.get_org_entity_ids(economyv2.ORG_TYPE_FIRM)
175
186
  firm_id = await self.memory.status.get('firm_id')
176
- bank_id = await self.memory.status.get('bank_id')
187
+ bank_id = await self.economy_client.get_org_entity_ids(economyv2.ORG_TYPE_BANK)
188
+ bank_id = bank_id[0]
177
189
  name = await self.memory.status.get('name')
178
190
  age = await self.memory.status.get('age')
179
191
  city = await self.memory.status.get('city')
180
192
  job = await self.memory.status.get('occupation')
181
- skill = await self.memory.status.get('work_skill')
182
- consumption = await self.memory.status.get('consumption_currency')
193
+ skill = await self.economy_client.get(agent_id, 'skill')
194
+ consumption = await self.economy_client.get(agent_id, 'consumption')
183
195
  tax_paid = await self.memory.status.get('tax_paid')
184
- price = await self.economy_client.get(firm_id, 'price')
196
+ prices = []
197
+ for firm_id in firms_id:
198
+ price = await self.economy_client.get(firm_id, 'price')
199
+ prices.append(price)
200
+ price = np.mean(prices)
185
201
  wealth = await self.economy_client.get(agent_id, 'currency')
186
202
  interest_rate = await self.economy_client.get(bank_id, 'interest_rate')
187
203
 
@@ -232,27 +248,27 @@ class MonthPlanBlock(Block):
232
248
  except:
233
249
  self.llm_error += 1
234
250
 
235
- skill = await self.memory.status.get('work_skill')
251
+ work_skill = await self.economy_client.get(agent_id, 'skill')
236
252
  work_propensity = await self.memory.status.get('work_propensity')
237
253
  consumption_propensity = await self.memory.status.get('consumption_propensity')
238
254
  work_hours = work_propensity * num_labor_hours
239
- await self.memory.status.update('income_currency', work_hours * skill)
255
+ income = await self.economy_client.get(agent_id, 'income')
256
+ income += work_hours * work_skill
257
+
240
258
  wealth = await self.economy_client.get(agent_id, 'currency')
241
- await self.economy_client.update(agent_id, 'currency', wealth + work_hours * skill)
259
+ wealth += work_hours * work_skill
260
+ await self.economy_client.update(agent_id, 'currency', wealth)
242
261
  await self.economy_client.add_delta_value(firm_id, 'inventory', int(work_hours*productivity_per_labor))
243
262
 
244
263
  if UBI and self.forward_times >= 96:
245
- income_currency = await self.memory.status.get('income_currency')
246
- await self.memory.status.update('income_currency', income_currency + UBI)
247
- wealth = await self.economy_client.get(agent_id, 'currency')
248
- await self.economy_client.update(agent_id, 'currency', wealth + UBI)
264
+ income += UBI
265
+ wealth += UBI
249
266
 
250
- wealth = await self.economy_client.get(agent_id, 'currency')
251
267
  await self.memory.status.update('to_consumption_currency', consumption_propensity*wealth)
252
268
 
253
- await self.memory.status.update('consumption_currency', 0)
254
- await self.memory.status.update('goods_demand', 0)
255
- await self.memory.status.update('goods_consumption', 0)
269
+ await self.economy_client.update(agent_id, 'consumption', 0)
270
+ await self.economy_client.update(agent_id, 'income', income)
271
+ await self.economy_client.update(agent_id, 'currency', wealth)
256
272
 
257
273
  if self.forward_times % 3 == 0:
258
274
  obs_prompt = f'''
@@ -312,6 +328,4 @@ class MonthPlanBlock(Block):
312
328
  obs_prompt = prettify_document(obs_prompt)
313
329
  content = await self.llm.atext_request([{'role': 'user', 'content': obs_prompt}], timeout=300)
314
330
  await self.memory.status.update('ubi_opinion', [content], mode='merge')
315
-
316
- self.forward_times += 1
317
- await self.memory.status.update('forward', self.forward_times)
331
+