pycityagent 2.0.0a94__cp311-cp311-macosx_11_0_arm64.whl → 2.0.0a96__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 (51) hide show
  1. pycityagent/agent/agent.py +5 -5
  2. pycityagent/agent/agent_base.py +1 -6
  3. pycityagent/cityagent/__init__.py +6 -5
  4. pycityagent/cityagent/bankagent.py +2 -2
  5. pycityagent/cityagent/blocks/__init__.py +4 -4
  6. pycityagent/cityagent/blocks/cognition_block.py +7 -4
  7. pycityagent/cityagent/blocks/economy_block.py +227 -135
  8. pycityagent/cityagent/blocks/mobility_block.py +70 -27
  9. pycityagent/cityagent/blocks/needs_block.py +11 -12
  10. pycityagent/cityagent/blocks/other_block.py +2 -2
  11. pycityagent/cityagent/blocks/plan_block.py +22 -24
  12. pycityagent/cityagent/blocks/social_block.py +15 -17
  13. pycityagent/cityagent/blocks/utils.py +3 -2
  14. pycityagent/cityagent/firmagent.py +1 -1
  15. pycityagent/cityagent/governmentagent.py +1 -1
  16. pycityagent/cityagent/initial.py +1 -1
  17. pycityagent/cityagent/memory_config.py +0 -1
  18. pycityagent/cityagent/message_intercept.py +7 -8
  19. pycityagent/cityagent/nbsagent.py +1 -1
  20. pycityagent/cityagent/societyagent.py +1 -2
  21. pycityagent/configs/__init__.py +18 -0
  22. pycityagent/configs/exp_config.py +202 -0
  23. pycityagent/configs/sim_config.py +251 -0
  24. pycityagent/configs/utils.py +17 -0
  25. pycityagent/environment/__init__.py +2 -0
  26. pycityagent/{economy → environment/economy}/econ_client.py +14 -32
  27. pycityagent/environment/sim/sim_env.py +17 -24
  28. pycityagent/environment/simulator.py +36 -113
  29. pycityagent/llm/__init__.py +1 -2
  30. pycityagent/llm/llm.py +54 -167
  31. pycityagent/memory/memory.py +13 -12
  32. pycityagent/message/message_interceptor.py +5 -4
  33. pycityagent/message/messager.py +3 -5
  34. pycityagent/metrics/__init__.py +1 -1
  35. pycityagent/metrics/mlflow_client.py +20 -17
  36. pycityagent/pycityagent-sim +0 -0
  37. pycityagent/simulation/agentgroup.py +18 -20
  38. pycityagent/simulation/simulation.py +157 -210
  39. pycityagent/survey/manager.py +0 -2
  40. pycityagent/utils/__init__.py +3 -0
  41. pycityagent/utils/config_const.py +20 -0
  42. pycityagent/workflow/__init__.py +1 -2
  43. pycityagent/workflow/block.py +0 -3
  44. {pycityagent-2.0.0a94.dist-info → pycityagent-2.0.0a96.dist-info}/METADATA +7 -24
  45. {pycityagent-2.0.0a94.dist-info → pycityagent-2.0.0a96.dist-info}/RECORD +50 -46
  46. pycityagent/llm/llmconfig.py +0 -18
  47. /pycityagent/{economy → environment/economy}/__init__.py +0 -0
  48. {pycityagent-2.0.0a94.dist-info → pycityagent-2.0.0a96.dist-info}/LICENSE +0 -0
  49. {pycityagent-2.0.0a94.dist-info → pycityagent-2.0.0a96.dist-info}/WHEEL +0 -0
  50. {pycityagent-2.0.0a94.dist-info → pycityagent-2.0.0a96.dist-info}/entry_points.txt +0 -0
  51. {pycityagent-2.0.0a94.dist-info → pycityagent-2.0.0a96.dist-info}/top_level.txt +0 -0
@@ -1,29 +1,27 @@
1
+ import asyncio
1
2
  import json
3
+ import logging
4
+ import numbers
5
+ import pickle as pkl
2
6
  import random
3
- from pycityagent.llm.llm import LLM
4
- from pycityagent.workflow.block import Block
5
- from pycityagent.memory import Memory
6
- import pycityproto.city.economy.v2.economy_pb2 as economyv2
7
7
 
8
- from .utils import clean_json_response, TIME_ESTIMATE_PROMPT
8
+ import numpy as np
9
+ import pycityproto.city.economy.v2.economy_pb2 as economyv2
9
10
 
10
- from .dispatcher import BlockDispatcher
11
+ from pycityagent.environment import EconomyClient
11
12
  from pycityagent.environment.simulator import Simulator
12
13
  from pycityagent.llm import LLM
14
+ from pycityagent.llm.llm import LLM
13
15
  from pycityagent.memory import Memory
14
16
  from pycityagent.workflow import Block
15
- import random
16
- import logging
17
- logger = logging.getLogger("pycityagent")
18
- import pickle as pkl
19
-
17
+ from pycityagent.workflow.block import Block
20
18
  from pycityagent.workflow.prompt import FormatPrompt
21
- from pycityagent.workflow import Block
22
- from pycityagent.economy import EconomyClient
19
+
20
+ from .dispatcher import BlockDispatcher
23
21
  from .utils import *
24
- import numbers
25
- import numpy as np
26
- import asyncio
22
+ from .utils import TIME_ESTIMATE_PROMPT, clean_json_response
23
+
24
+ logger = logging.getLogger("pycityagent")
27
25
 
28
26
  def softmax(x, gamma=1.0):
29
27
  if not isinstance(x, np.ndarray):
@@ -32,157 +30,217 @@ def softmax(x, gamma=1.0):
32
30
  e_x = np.exp(x - np.max(x))
33
31
  return e_x / e_x.sum(axis=-1, keepdims=True)
34
32
 
33
+
35
34
  class WorkBlock(Block):
36
35
  """WorkPlace Block"""
36
+
37
37
  def __init__(self, llm: LLM, memory: Memory, simulator: Simulator):
38
38
  super().__init__("WorkBlock", llm=llm, memory=memory, simulator=simulator)
39
39
  self.description = "Do work related tasks"
40
40
  self.guidance_prompt = FormatPrompt(template=TIME_ESTIMATE_PROMPT)
41
+
41
42
  async def forward(self, step, context):
42
43
  self.guidance_prompt.format(
43
- plan=context['plan'],
44
- intention=step['intention'],
44
+ plan=context["plan"],
45
+ intention=step["intention"],
45
46
  emotion_types=await self.memory.status.get("emotion_types"),
46
47
  )
47
- result = await self.llm.atext_request(self.guidance_prompt.to_dialog())
48
+ result = await self.llm.atext_request(self.guidance_prompt.to_dialog(), response_format={"type": "json_object"})
48
49
  result = clean_json_response(result)
49
50
  try:
50
51
  result = json.loads(result)
51
- time = result['time']
52
+ time = result["time"]
52
53
  start_time = await self.simulator.get_time(format_time=True)
53
- await self.memory.status.update("working_experience", [f"Start from {start_time}, worked {time} minutes on {step['intention']}"], mode="merge")
54
+ await self.memory.status.update(
55
+ "working_experience",
56
+ [
57
+ f"Start from {start_time}, worked {time} minutes on {step['intention']}"
58
+ ],
59
+ mode="merge",
60
+ )
54
61
  work_hour_finish = await self.memory.status.get("work_hour_finish")
55
- work_hour_finish += float(time/60)
56
- node_id = await self.memory.stream.add_economy(description=f"I worked {time} minutes on {step['intention']}")
62
+ work_hour_finish += float(time / 60)
63
+ node_id = await self.memory.stream.add_economy(
64
+ description=f"I worked {time} minutes on {step['intention']}"
65
+ )
57
66
  await self.memory.status.update("work_hour_finish", work_hour_finish)
58
67
  return {
59
- 'success': True,
60
- 'evaluation': f'work: {step["intention"]}',
61
- 'consumed_time': time,
62
- 'node_id': node_id
68
+ "success": True,
69
+ "evaluation": f'work: {step["intention"]}',
70
+ "consumed_time": time,
71
+ "node_id": node_id,
63
72
  }
64
73
  except Exception as e:
65
74
  logger.warning(f"解析时间评估响应时发生错误: {str(e)}, 原始结果: {result}")
66
- time = random.randint(1, 5)*60
75
+ time = random.randint(1, 5) * 60
67
76
  start_time = await self.simulator.get_time(format_time=True)
68
- await self.memory.status.update("working_experience", [f"Start from {start_time}, worked {time} minutes on {step['intention']}"], mode="merge")
77
+ await self.memory.status.update(
78
+ "working_experience",
79
+ [
80
+ f"Start from {start_time}, worked {time} minutes on {step['intention']}"
81
+ ],
82
+ mode="merge",
83
+ )
69
84
  work_hour_finish = await self.memory.status.get("work_hour_finish")
70
- node_id = await self.memory.stream.add_economy(description=f"I worked {time} minutes on {step['intention']}")
71
- work_hour_finish += float(time/60)
85
+ node_id = await self.memory.stream.add_economy(
86
+ description=f"I worked {time} minutes on {step['intention']}"
87
+ )
88
+ work_hour_finish += float(time / 60)
72
89
  await self.memory.status.update("work_hour_finish", work_hour_finish)
73
90
  return {
74
- 'success': True,
75
- 'evaluation': f'work: {step["intention"]}',
76
- 'consumed_time': time,
77
- 'node_id': node_id
91
+ "success": True,
92
+ "evaluation": f'work: {step["intention"]}',
93
+ "consumed_time": time,
94
+ "node_id": node_id,
78
95
  }
79
-
96
+
97
+
80
98
  class ConsumptionBlock(Block):
81
99
  """
82
100
  determine the consumption amount, and items
83
101
  """
84
- def __init__(self, llm: LLM, memory: Memory, simulator: Simulator, economy_client: EconomyClient):
85
- super().__init__("ConsumptionBlock", llm=llm, memory=memory, simulator=simulator)
102
+
103
+ def __init__(
104
+ self,
105
+ llm: LLM,
106
+ memory: Memory,
107
+ simulator: Simulator,
108
+ economy_client: EconomyClient,
109
+ ):
110
+ super().__init__(
111
+ "ConsumptionBlock", llm=llm, memory=memory, simulator=simulator
112
+ )
86
113
  self.economy_client = economy_client
87
114
  self.forward_times = 0
88
115
  self.description = "Used to determine the consumption amount, and items"
89
116
 
90
117
  async def forward(self, step, context):
91
118
  self.forward_times += 1
92
- agent_id = await self.memory.status.get("id") # agent_id
119
+ agent_id = await self.memory.status.get("id") # agent_id
93
120
  firms_id = await self.economy_client.get_org_entity_ids(economyv2.ORG_TYPE_FIRM)
94
121
  intention = step["intention"]
95
- month_consumption = await self.memory.status.get('to_consumption_currency')
96
- consumption_currency = await self.economy_client.get(agent_id, 'consumption')
122
+ month_consumption = await self.memory.status.get("to_consumption_currency")
123
+ consumption_currency = await self.economy_client.get(agent_id, "consumption")
97
124
  if consumption_currency >= month_consumption:
98
- node_id = await self.memory.stream.add_economy(description=f"I have passed the monthly consumption limit, so I will not consume.")
125
+ node_id = await self.memory.stream.add_economy(
126
+ description=f"I have passed the monthly consumption limit, so I will not consume."
127
+ )
99
128
  return {
100
- 'success': False,
101
- 'evaluation': f"I have passed the monthly consumption limit, so I will not consume.",
102
- 'consumed_time': 0,
103
- 'node_id': node_id
129
+ "success": False,
130
+ "evaluation": f"I have passed the monthly consumption limit, so I will not consume.",
131
+ "consumed_time": 0,
132
+ "node_id": node_id,
104
133
  }
105
- consumption = min(month_consumption/1, month_consumption-consumption_currency)
134
+ consumption = min(
135
+ month_consumption / 1, month_consumption - consumption_currency
136
+ )
106
137
  prices = []
107
138
  for this_firm_id in firms_id:
108
- price = await self.economy_client.get(this_firm_id, 'price')
139
+ price = await self.economy_client.get(this_firm_id, "price")
109
140
  prices.append(price)
110
- consumption_each_firm = consumption*softmax(prices, gamma=-0.01)
141
+ consumption_each_firm = consumption * softmax(prices, gamma=-0.01)
111
142
  demand_each_firm = []
112
143
  for i in range(len(firms_id)):
113
- demand_each_firm.append(int(consumption_each_firm[i]//prices[i]))
114
- real_consumption = await self.economy_client.calculate_consumption(firms_id, agent_id, demand_each_firm)
115
- node_id = await self.memory.stream.add_economy(description=f"I bought some goods, and spent {real_consumption:.1f} on {intention}")
144
+ demand_each_firm.append(int(consumption_each_firm[i] // prices[i]))
145
+ real_consumption = await self.economy_client.calculate_consumption(
146
+ firms_id, agent_id, demand_each_firm
147
+ )
148
+ node_id = await self.memory.stream.add_economy(
149
+ description=f"I bought some goods, and spent {real_consumption:.1f} on {intention}"
150
+ )
116
151
  evaluation = {
117
- 'success': True,
118
- 'evaluation': f"I bought some goods, and spent {real_consumption:.1f} on {intention}",
119
- 'consumed_time': 20,
120
- 'node_id': node_id
152
+ "success": True,
153
+ "evaluation": f"I bought some goods, and spent {real_consumption:.1f} on {intention}",
154
+ "consumed_time": 20,
155
+ "node_id": node_id,
121
156
  }
122
157
  return evaluation
123
-
158
+
159
+
124
160
  class EconomyNoneBlock(Block):
125
161
  """
126
162
  Do anything else
127
163
  NoneBlock
128
164
  """
165
+
129
166
  def __init__(self, llm: LLM, memory: Memory):
130
167
  super().__init__("NoneBlock", llm=llm, memory=memory)
131
168
  self.description = "Do anything else"
132
169
 
133
170
  async def forward(self, step, context):
134
- node_id = await self.memory.stream.add_economy(description=f"I {step['intention']}")
171
+ node_id = await self.memory.stream.add_economy(
172
+ description=f"I {step['intention']}"
173
+ )
135
174
  return {
136
- 'success': True,
137
- 'evaluation': f'Finished{step["intention"]}',
138
- 'consumed_time': 0,
139
- 'node_id': node_id
175
+ "success": True,
176
+ "evaluation": f'Finished{step["intention"]}',
177
+ "consumed_time": 0,
178
+ "node_id": node_id,
140
179
  }
141
180
 
181
+
142
182
  class EconomyBlock(Block):
143
183
  work_block: WorkBlock
144
184
  consumption_block: ConsumptionBlock
145
185
  none_block: EconomyNoneBlock
146
186
 
147
- def __init__(self, llm: LLM, memory: Memory, simulator: Simulator, economy_client: EconomyClient):
187
+ def __init__(
188
+ self,
189
+ llm: LLM,
190
+ memory: Memory,
191
+ simulator: Simulator,
192
+ economy_client: EconomyClient,
193
+ ):
148
194
  super().__init__("EconomyBlock", llm=llm, memory=memory, simulator=simulator)
149
195
  self.economy_client = economy_client
150
196
  self.work_block = WorkBlock(llm, memory, simulator)
151
- self.consumption_block = ConsumptionBlock(llm, memory, simulator, economy_client)
197
+ self.consumption_block = ConsumptionBlock(
198
+ llm, memory, simulator, economy_client
199
+ )
152
200
  self.none_block = EconomyNoneBlock(llm, memory)
153
201
  self.trigger_time = 0
154
202
  self.token_consumption = 0
155
203
  self.dispatcher = BlockDispatcher(llm)
156
- self.dispatcher.register_blocks([self.work_block, self.consumption_block, self.none_block])
204
+ self.dispatcher.register_blocks(
205
+ [self.work_block, self.consumption_block, self.none_block]
206
+ )
157
207
 
158
- async def forward(self, step, context):
208
+ async def forward(self, step, context):
159
209
  self.trigger_time += 1
160
210
  selected_block = await self.dispatcher.dispatch(step)
161
- result = await selected_block.forward(step, context) # type: ignore
211
+ result = await selected_block.forward(step, context) # type: ignore
162
212
  return result
163
-
213
+
214
+
164
215
  class MonthPlanBlock(Block):
165
216
  """Monthly Planning"""
217
+
166
218
  configurable_fields = [
167
219
  "UBI",
168
220
  "num_labor_hours",
169
221
  "productivity_per_labor",
170
- "time_diff"
222
+ "time_diff",
171
223
  ]
172
224
  default_values = {
173
225
  "UBI": 0,
174
226
  "num_labor_hours": 168,
175
227
  "productivity_per_labor": 1,
176
- "time_diff": 30 * 24 * 60 * 60
228
+ "time_diff": 30 * 24 * 60 * 60,
177
229
  }
178
230
  fields_description = {
179
231
  "UBI": "Universal Basic Income",
180
232
  "num_labor_hours": "Number of labor hours per month",
181
233
  "productivity_per_labor": "Productivity per labor hour",
182
- "time_diff": "Time difference between two triggers"
234
+ "time_diff": "Time difference between two triggers",
183
235
  }
184
236
 
185
- def __init__(self, llm: LLM, memory: Memory, simulator: Simulator, economy_client: EconomyClient):
237
+ def __init__(
238
+ self,
239
+ llm: LLM,
240
+ memory: Memory,
241
+ simulator: Simulator,
242
+ economy_client: EconomyClient,
243
+ ):
186
244
  super().__init__("MonthPlanBlock", llm=llm, memory=memory, simulator=simulator)
187
245
  self.economy_client = economy_client
188
246
  self.llm_error = 0
@@ -194,57 +252,66 @@ class MonthPlanBlock(Block):
194
252
  self.num_labor_hours = 168
195
253
  self.productivity_per_labor = 1
196
254
  self.time_diff = 30 * 24 * 60 * 60
197
-
255
+
198
256
  async def month_trigger(self):
199
257
  now_time = await self.simulator.get_time()
200
- if self.last_time_trigger is None or now_time - self.last_time_trigger >= self.time_diff:
258
+ if (
259
+ self.last_time_trigger is None
260
+ or now_time - self.last_time_trigger >= self.time_diff
261
+ ):
201
262
  self.last_time_trigger = now_time
202
263
  return True
203
264
  return False
204
-
265
+
205
266
  async def forward(self):
206
267
  if await self.month_trigger():
207
268
  agent_id = await self.memory.status.get("id")
208
- firms_id = await self.economy_client.get_org_entity_ids(economyv2.ORG_TYPE_FIRM)
209
- firm_id = await self.memory.status.get('firm_id')
210
- bank_id = await self.economy_client.get_org_entity_ids(economyv2.ORG_TYPE_BANK)
269
+ firms_id = await self.economy_client.get_org_entity_ids(
270
+ economyv2.ORG_TYPE_FIRM
271
+ )
272
+ firm_id = await self.memory.status.get("firm_id")
273
+ bank_id = await self.economy_client.get_org_entity_ids(
274
+ economyv2.ORG_TYPE_BANK
275
+ )
211
276
  bank_id = bank_id[0]
212
- name = await self.memory.status.get('name')
213
- age = await self.memory.status.get('age')
214
- city = await self.memory.status.get('city')
215
- job = await self.memory.status.get('occupation')
216
- skill = await self.economy_client.get(agent_id, 'skill')
217
- consumption = await self.economy_client.get(agent_id, 'consumption')
218
- tax_paid = await self.memory.status.get('tax_paid')
277
+ name = await self.memory.status.get("name")
278
+ age = await self.memory.status.get("age")
279
+ city = await self.memory.status.get("city")
280
+ job = await self.memory.status.get("occupation")
281
+ skill = await self.economy_client.get(agent_id, "skill")
282
+ consumption = await self.economy_client.get(agent_id, "consumption")
283
+ tax_paid = await self.memory.status.get("tax_paid")
219
284
  prices = []
220
285
  for this_firm_id in firms_id:
221
- price = await self.economy_client.get(this_firm_id, 'price')
286
+ price = await self.economy_client.get(this_firm_id, "price")
222
287
  prices.append(price)
223
288
  price = np.mean(prices)
224
- wealth = await self.economy_client.get(agent_id, 'currency')
225
- interest_rate = await self.economy_client.get(bank_id, 'interest_rate')
226
-
227
- problem_prompt = f'''
289
+ wealth = await self.economy_client.get(agent_id, "currency")
290
+ interest_rate = await self.economy_client.get(bank_id, "interest_rate")
291
+
292
+ problem_prompt = f"""
228
293
  You're {name}, a {age}-year-old individual living in {city}. As with all Americans, a portion of your monthly income is taxed by the federal government. This taxation system is tiered, income is taxed cumulatively within defined brackets, combined with a redistributive policy: after collection, the government evenly redistributes the tax revenue back to all citizens, irrespective of their earnings.
229
- '''
230
- job_prompt = f'''
294
+ """
295
+ job_prompt = f"""
231
296
  In the previous month, you worked as a(an) {job}. If you continue working this month, your expected hourly income will be ${skill:.2f}.
232
- '''
233
- consumption_propensity = await self.memory.status.get('consumption_propensity')
297
+ """
298
+ consumption_propensity = await self.memory.status.get(
299
+ "consumption_propensity"
300
+ )
234
301
  if (consumption <= 0) and (consumption_propensity > 0):
235
- consumption_prompt = f'''
302
+ consumption_prompt = f"""
236
303
  Besides, you had no consumption due to shortage of goods.
237
- '''
304
+ """
238
305
  else:
239
- consumption_prompt = f'''
306
+ consumption_prompt = f"""
240
307
  Besides, your consumption was ${consumption:.2f}.
241
- '''
242
- tax_prompt = f'''Your tax deduction amounted to ${tax_paid:.2f}, and the government uses the tax revenue to provide social services to all citizens.'''
308
+ """
309
+ tax_prompt = f"""Your tax deduction amounted to ${tax_paid:.2f}, and the government uses the tax revenue to provide social services to all citizens."""
243
310
  if self.UBI and self.forward_times >= 96:
244
- tax_prompt = f'{tax_prompt} Specifically, the government directly provides ${self.UBI} per capita in each month.'
245
- price_prompt = f'''Meanwhile, in the consumption market, the average price of essential goods is now at ${price:.2f}.'''
311
+ tax_prompt = f"{tax_prompt} Specifically, the government directly provides ${self.UBI} per capita in each month."
312
+ price_prompt = f"""Meanwhile, in the consumption market, the average price of essential goods is now at ${price:.2f}."""
246
313
  job_prompt = prettify_document(job_prompt)
247
- obs_prompt = f'''
314
+ obs_prompt = f"""
248
315
  {problem_prompt} {job_prompt} {consumption_prompt} {tax_prompt} {price_prompt}
249
316
  Your current savings account balance is ${wealth:.2f}. Interest rates, as set by your bank, stand at {interest_rate*100:.2f}%.
250
317
  Your goal is to maximize your utility by deciding how much to work and how much to consume. Your utility is determined by your consumption, income, saving, social service recieved and leisure time. You will spend the time you do not work on leisure activities.
@@ -254,47 +321,68 @@ class MonthPlanBlock(Block):
254
321
  'consumption': a value between 0 and 1, indicating the proportion of all your savings and income you intend to spend on essential goods
255
322
  }}
256
323
  Any other output words are NOT allowed.
257
- '''
324
+ """
258
325
  obs_prompt = prettify_document(obs_prompt)
259
326
  try:
260
- await self.memory.status.update('dialog_queue', [{'role': 'user', 'content': obs_prompt}], mode='merge')
261
- dialog_queue = await self.memory.status.get('dialog_queue')
327
+ await self.memory.status.update(
328
+ "dialog_queue",
329
+ [{"role": "user", "content": obs_prompt}],
330
+ mode="merge",
331
+ )
332
+ dialog_queue = await self.memory.status.get("dialog_queue")
262
333
  content = await self.llm.atext_request(list(dialog_queue), timeout=300)
263
- await self.memory.status.update('dialog_queue', [{'role': 'assistant', 'content': content}], mode='merge')
334
+ await self.memory.status.update(
335
+ "dialog_queue",
336
+ [{"role": "assistant", "content": content}],
337
+ mode="merge",
338
+ )
264
339
  propensity_dict = extract_dict_from_string(content)[0]
265
- work_propensity, consumption_propensity = propensity_dict['work'], propensity_dict['consumption']
266
- if isinstance(work_propensity, numbers.Number) and isinstance(consumption_propensity, numbers.Number):
267
- await self.memory.status.update('work_propensity', work_propensity)
268
- await self.memory.status.update('consumption_propensity', consumption_propensity)
340
+ work_propensity, consumption_propensity = (
341
+ propensity_dict["work"],
342
+ propensity_dict["consumption"],
343
+ )
344
+ if isinstance(work_propensity, numbers.Number) and isinstance(
345
+ consumption_propensity, numbers.Number
346
+ ):
347
+ await self.memory.status.update("work_propensity", work_propensity)
348
+ await self.memory.status.update(
349
+ "consumption_propensity", consumption_propensity
350
+ )
269
351
  else:
270
352
  self.llm_error += 1
271
353
  except:
272
354
  self.llm_error += 1
273
-
274
- work_skill = await self.economy_client.get(agent_id, 'skill')
275
- work_propensity = await self.memory.status.get('work_propensity')
276
- consumption_propensity = await self.memory.status.get('consumption_propensity')
355
+
356
+ work_skill = await self.economy_client.get(agent_id, "skill")
357
+ work_propensity = await self.memory.status.get("work_propensity")
358
+ consumption_propensity = await self.memory.status.get(
359
+ "consumption_propensity"
360
+ )
277
361
  work_hours = work_propensity * self.num_labor_hours
278
362
  # income = await self.economy_client.get(agent_id, 'income')
279
363
  income = work_hours * work_skill
280
-
281
- wealth = await self.economy_client.get(agent_id, 'currency')
364
+
365
+ wealth = await self.economy_client.get(agent_id, "currency")
282
366
  wealth += work_hours * work_skill
283
- await self.economy_client.update(agent_id, 'currency', wealth)
284
- await self.economy_client.add_delta_value(firm_id, 'inventory', int(work_hours*self.productivity_per_labor))
285
-
367
+ await self.economy_client.update(agent_id, "currency", wealth)
368
+ await self.economy_client.add_delta_value(
369
+ firm_id, "inventory", int(work_hours * self.productivity_per_labor)
370
+ )
371
+
286
372
  if self.UBI and self.forward_times >= 96:
287
373
  income += self.UBI
288
374
  wealth += self.UBI
289
375
 
290
- await self.memory.status.update('to_consumption_currency', consumption_propensity*wealth)
291
-
292
- await self.economy_client.update(agent_id, 'consumption', 0)
293
- await self.economy_client.update(agent_id, 'income', income)
294
- await self.economy_client.update(agent_id, 'currency', wealth)
295
-
376
+ await self.memory.status.update(
377
+ "to_consumption_currency", consumption_propensity * wealth
378
+ )
379
+
380
+ await self.economy_client.update(agent_id, "consumption", 0)
381
+ await self.economy_client.update(agent_id, "income", income)
382
+ await self.economy_client.update(agent_id, "currency", wealth)
383
+
296
384
  if self.forward_times % 3 == 0:
297
- obs_prompt = f'''
385
+ obs_prompt = f"""
298
386
  {problem_prompt} {job_prompt} {consumption_prompt} {tax_prompt} {price_prompt}
299
387
  Your current savings account balance is ${wealth:.2f}. Interest rates, as set by your bank, stand at {interest_rate*100:.2f}%.
300
388
  Please fill in the following questionnaire:
@@ -325,11 +413,13 @@ class MonthPlanBlock(Block):
325
413
  Statement 20: I could not get "going".
326
414
  Please response with json format with keys being numbers 1-20 and values being one of "Rarely", "Some", "Occasionally", "Most".
327
415
  Any other output words are NOT allowed.
328
- '''
416
+ """
329
417
  obs_prompt = prettify_document(obs_prompt)
330
- content = await self.llm.atext_request([{'role': 'user', 'content': obs_prompt}], timeout=300)
418
+ content = await self.llm.atext_request(
419
+ [{"role": "user", "content": obs_prompt}], timeout=300
420
+ )
331
421
  inverse_score_items = [3, 8, 12, 16]
332
- category2score = {'rarely': 0, 'some': 1, 'occasionally': 2, 'most': 3}
422
+ category2score = {"rarely": 0, "some": 1, "occasionally": 2, "most": 3}
333
423
  try:
334
424
  content = extract_dict_from_string(content)[0]
335
425
  for k in content:
@@ -338,18 +428,20 @@ class MonthPlanBlock(Block):
338
428
  else:
339
429
  content[k] = category2score[content[k].lower()]
340
430
  depression = sum(list(content.values()))
341
- await self.memory.status.update('depression', depression)
431
+ await self.memory.status.update("depression", depression)
342
432
  except:
343
433
  self.llm_error += 1
344
434
 
345
435
  if self.UBI and self.forward_times >= 96 and self.forward_times % 12 == 0:
346
- obs_prompt = f'''
436
+ obs_prompt = f"""
347
437
  {problem_prompt} {job_prompt} {consumption_prompt} {tax_prompt} {price_prompt}
348
438
  Your current savings account balance is ${wealth:.2f}. Interest rates, as set by your bank, stand at {interest_rate*100:.2f}%.
349
439
  What's your opinion on the UBI policy, including the advantages and disadvantages?
350
- '''
440
+ """
351
441
  obs_prompt = prettify_document(obs_prompt)
352
- content = await self.llm.atext_request([{'role': 'user', 'content': obs_prompt}], timeout=300)
353
- await self.memory.status.update('ubi_opinion', [content], mode='merge')
442
+ content = await self.llm.atext_request(
443
+ [{"role": "user", "content": obs_prompt}], timeout=300
444
+ )
445
+ await self.memory.status.update("ubi_opinion", [content], mode="merge")
354
446
 
355
- self.forward_times += 1
447
+ self.forward_times += 1