pycityagent 2.0.0a52__cp312-cp312-macosx_11_0_arm64.whl → 2.0.0a53__cp312-cp312-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 (36) hide show
  1. pycityagent/agent/agent.py +48 -62
  2. pycityagent/agent/agent_base.py +66 -53
  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 +44 -56
  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/nbsagent.py +6 -29
  17. pycityagent/cityagent/societyagent.py +204 -119
  18. pycityagent/environment/sim/client.py +10 -1
  19. pycityagent/environment/sim/clock_service.py +2 -2
  20. pycityagent/environment/sim/pause_service.py +61 -0
  21. pycityagent/environment/simulator.py +17 -12
  22. pycityagent/llm/embeddings.py +0 -24
  23. pycityagent/memory/faiss_query.py +29 -26
  24. pycityagent/memory/memory.py +720 -272
  25. pycityagent/pycityagent-sim +0 -0
  26. pycityagent/simulation/agentgroup.py +92 -99
  27. pycityagent/simulation/simulation.py +115 -40
  28. pycityagent/tools/tool.py +7 -9
  29. pycityagent/workflow/block.py +11 -4
  30. {pycityagent-2.0.0a52.dist-info → pycityagent-2.0.0a53.dist-info}/METADATA +1 -1
  31. {pycityagent-2.0.0a52.dist-info → pycityagent-2.0.0a53.dist-info}/RECORD +35 -35
  32. pycityagent/cityagent/blocks/time_block.py +0 -116
  33. {pycityagent-2.0.0a52.dist-info → pycityagent-2.0.0a53.dist-info}/LICENSE +0 -0
  34. {pycityagent-2.0.0a52.dist-info → pycityagent-2.0.0a53.dist-info}/WHEEL +0 -0
  35. {pycityagent-2.0.0a52.dist-info → pycityagent-2.0.0a53.dist-info}/entry_points.txt +0 -0
  36. {pycityagent-2.0.0a52.dist-info → pycityagent-2.0.0a53.dist-info}/top_level.txt +0 -0
@@ -21,20 +21,18 @@ from pycityagent.workflow import Block
21
21
  from pycityagent.economy import EconomyClient
22
22
  from .utils import *
23
23
  import numbers
24
- import asyncio
25
24
 
26
-
27
-
28
-
29
25
  class WorkBlock(Block):
26
+ """WorkPlace Block"""
30
27
  def __init__(self, llm: LLM, memory: Memory, simulator: Simulator):
31
- super().__init__("WorkBlock", llm, memory, simulator)
28
+ super().__init__("WorkBlock", llm=llm, memory=memory, simulator=simulator)
32
29
  self.description = "Do work"
33
30
  self.guidance_prompt = FormatPrompt(template=TIME_ESTIMATE_PROMPT)
34
31
  async def forward(self, step, context):
35
32
  self.guidance_prompt.format(
36
33
  plan=context['plan'],
37
- intention=step['intention']
34
+ intention=step['intention'],
35
+ emotion_types=await self.memory.status.get("emotion_types"),
38
36
  )
39
37
  result = await self.llm.atext_request(self.guidance_prompt.to_dialog())
40
38
  result = clean_json_response(result)
@@ -42,108 +40,94 @@ class WorkBlock(Block):
42
40
  result = json.loads(result)
43
41
  time = result['time']
44
42
  start_time = await self.simulator.get_time(format_time=True)
45
- await self.memory.update("working_experience", [f"Start from {start_time}, worked {time} minutes on {step['intention']}"], mode="merge")
46
- work_hour_finish = await self.memory.get("work_hour_finish")
43
+ await self.memory.status.update("working_experience", [f"Start from {start_time}, worked {time} minutes on {step['intention']}"], mode="merge")
44
+ work_hour_finish = await self.memory.status.get("work_hour_finish")
47
45
  work_hour_finish += float(time/60)
48
- await self.memory.update("work_hour_finish", work_hour_finish)
46
+ node_id = await self.memory.stream.add_economy(description=f"I worked {time} minutes on {step['intention']}")
47
+ await self.memory.status.update("work_hour_finish", work_hour_finish)
49
48
  return {
50
49
  'success': True,
51
- 'evaluation': f'工作:{step["intention"]}',
52
- 'consumed_time': time
50
+ 'evaluation': f'work: {step["intention"]}',
51
+ 'consumed_time': time,
52
+ 'node_id': node_id
53
53
  }
54
54
  except Exception as e:
55
55
  logger.warning(f"解析时间评估响应时发生错误: {str(e)}, 原始结果: {result}")
56
56
  time = random.randint(1, 5)*60
57
57
  start_time = await self.simulator.get_time(format_time=True)
58
- await self.memory.update("working_experience", [f"Start from {start_time}, worked {time} minutes on {step['intention']}"], mode="merge")
59
- work_hour_finish = await self.memory.get("work_hour_finish")
58
+ await self.memory.status.update("working_experience", [f"Start from {start_time}, worked {time} minutes on {step['intention']}"], mode="merge")
59
+ work_hour_finish = await self.memory.status.get("work_hour_finish")
60
+ node_id = await self.memory.stream.add_economy(description=f"I worked {time} minutes on {step['intention']}")
60
61
  work_hour_finish += float(time/60)
61
- await self.memory.update("work_hour_finish", work_hour_finish)
62
+ await self.memory.status.update("work_hour_finish", work_hour_finish)
62
63
  return {
63
64
  'success': True,
64
- 'evaluation': f'工作:{step["intention"]}',
65
- 'consumed_time': time
65
+ 'evaluation': f'work: {step["intention"]}',
66
+ 'consumed_time': time,
67
+ 'node_id': node_id
66
68
  }
67
69
 
68
70
  class ConsumptionBlock(Block):
69
71
  """
70
- determine the consumption place, time, amount, and items
72
+ determine the consumption amount, and items
71
73
  """
72
74
  def __init__(self, llm: LLM, memory: Memory, simulator: Simulator, economy_client: EconomyClient):
73
- super().__init__("ConsumptionBlock", llm, memory, simulator)
75
+ super().__init__("ConsumptionBlock", llm=llm, memory=memory, simulator=simulator)
74
76
  self.economy_client = economy_client
75
77
  self.forward_times = 0
76
- self.description = "Used to determine the consumption place, time, amount, and items"
78
+ self.description = "Used to determine the consumption amount, and items"
77
79
 
78
80
  async def forward(self, step, context):
79
81
  self.forward_times += 1
80
- agent_id = await self.memory.get("id") # agent_id
81
- firm_id = await self.memory.get('firm_id')
82
+ agent_id = await self.memory.status.get("id") # agent_id
83
+ firm_id = await self.memory.status.get('firm_id')
82
84
  intention = step["intention"]
83
- nowPlace = await self.memory.get('position')
84
- nowPlace = nowPlace['xy_position']
85
- nowPlace = (nowPlace['x'], nowPlace['y'])
86
- all_poi_types = self.simulator.get_poi_categories(nowPlace, 2000)
87
- if len(all_poi_types) == 0:
88
- all_poi_types.extend(['supermarket'])
89
- prompt = 'Your intention is to {intention}. Which type of POI do you want to go to? Select one and only one type from the following types: {all_poi_types}. Any other output is NOT acceptable.'
90
- prompt = FormatPrompt(prompt)
91
- prompt.format(intention=intention, all_poi_types=all_poi_types)
92
- poi_type = await self.llm.atext_request(prompt.to_dialog(), timeout=300)
93
- poi_type = poi_type.strip('[').strip(']')
94
- if poi_type not in all_poi_types:
95
- poi_type = random.choice(all_poi_types)
96
- around_pois = self.simulator.get_around_poi(nowPlace, 2000, poi_type)
97
- if len(around_pois) == 0:
98
- around_pois.extend(['沃尔玛', '家乐福', '华润万家', '物美'])
99
- prompt = """
100
- You're a {gender} and your education level is {education}.
101
- Your intention is to {intention} and you plan to consume for ${consumption}.
102
- The follwing are the places you can go to consume:
103
- {around_pois}
104
- Where should you go to make a purchase, when should you go, and what items will you spend on?
105
- Respond with this format: [place, time, items to buy]. Any other output is NOT acceptable.
106
- """
107
- prompt = FormatPrompt(prompt)
108
- data = {key: await self.memory.get(key) for key in ['gender', 'education']}
109
- data['around_pois'] = around_pois
110
- data['intention'] = intention
111
- month_consumption = await self.memory.get('to_consumption_currency')
112
- consumption_currency = await self.memory.get('consumption_currency')
85
+ month_consumption = await self.memory.status.get('to_consumption_currency')
86
+ consumption_currency = await self.memory.status.get('consumption_currency')
113
87
  if consumption_currency >= month_consumption:
114
- return {'Success': True, 'Evaluation': f"Consumption Done", 'consumed_time': 0}
115
- data['consumption'] = min(month_consumption/1, month_consumption-consumption_currency)
88
+ node_id = await self.memory.stream.add_economy(description=f"I have passed the monthly consumption limit, so I will not consume.")
89
+ return {
90
+ 'success': False,
91
+ 'evaluation': f"I have passed the monthly consumption limit, so I will not consume.",
92
+ 'consumed_time': 0,
93
+ 'node_id': node_id
94
+ }
95
+ consumption = min(month_consumption/1, month_consumption-consumption_currency)
116
96
  price = await self.economy_client.get(firm_id, 'price') # agent_id
117
97
  wealth = await self.economy_client.get(agent_id, 'currency')
118
- this_demand = int(data['consumption']//price)
98
+ this_demand = int(consumption//price)
119
99
  _, post_consumption_wealth = await self.economy_client.calculate_consumption(firm_id, [agent_id], [this_demand])
120
100
  post_consumption_wealth = post_consumption_wealth[0]
121
- await self.memory.update('consumption_currency', consumption_currency+wealth-post_consumption_wealth)
122
- goods_demand = await self.memory.get('goods_demand')
123
- goods_consumption = await self.memory.get('goods_consumption')
124
- await self.memory.update('goods_demand', goods_demand+this_demand)
125
- await self.memory.update('goods_consumption', goods_consumption+int((wealth-post_consumption_wealth)//price))
126
- prompt.format(**data)
127
- response = await self.llm.atext_request(prompt.to_dialog(), timeout=300)
128
- evaluation = {'success': True, 'evaluation': f"Consumption: {response}", 'consumed_time': 100}
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}")
107
+ evaluation = {
108
+ 'success': True,
109
+ 'evaluation': f"I bought some goods, and spent {this_demand} on {intention}",
110
+ 'consumed_time': 20,
111
+ 'node_id': node_id
112
+ }
129
113
  return evaluation
130
114
 
131
115
  class EconomyNoneBlock(Block):
132
116
  """
133
- Do nothing
117
+ Do anything else
134
118
  NoneBlock
135
119
  """
136
120
  def __init__(self, llm: LLM, memory: Memory):
137
- super().__init__("NoneBlock", llm, memory)
138
- self.description = "Do nothing"
139
- self.forward_times = 0
121
+ super().__init__("NoneBlock", llm=llm, memory=memory)
122
+ self.description = "Do anything else"
140
123
 
141
124
  async def forward(self, step, context):
142
- self.forward_times += 1
125
+ node_id = await self.memory.stream.add_economy(description=f"I {step['intention']}")
143
126
  return {
144
127
  'success': True,
145
- 'evaluation': f'完成执行{step["intention"]}',
146
- 'consumed_time': 0
128
+ 'evaluation': f'Finished{step["intention"]}',
129
+ 'consumed_time': 0,
130
+ 'node_id': node_id
147
131
  }
148
132
 
149
133
  class EconomyBlock(Block):
@@ -152,37 +136,26 @@ class EconomyBlock(Block):
152
136
  none_block: EconomyNoneBlock
153
137
 
154
138
  def __init__(self, llm: LLM, memory: Memory, simulator: Simulator, economy_client: EconomyClient):
155
- super().__init__("EconomyBlock", llm, memory, simulator)
139
+ super().__init__("EconomyBlock", llm=llm, memory=memory, simulator=simulator)
156
140
  self.economy_client = economy_client
157
- # 初始化所有块
158
141
  self.work_block = WorkBlock(llm, memory, simulator)
159
142
  self.consumption_block = ConsumptionBlock(llm, memory, simulator, economy_client)
160
143
  self.none_block = EconomyNoneBlock(llm, memory)
161
144
  self.trigger_time = 0
162
145
  self.token_consumption = 0
163
- # 初始化调度器
164
146
  self.dispatcher = BlockDispatcher(llm)
165
- # 注册所有块
166
147
  self.dispatcher.register_blocks([self.work_block, self.consumption_block, self.none_block])
167
148
 
168
149
  async def forward(self, step, context):
169
150
  self.trigger_time += 1
170
- consumption_start = self.llm.prompt_tokens_used + self.llm.completion_tokens_used
171
-
172
- # Select the appropriate sub-block using dispatcher
173
- # selected_block = await self.dispatcher.dispatch(step)
174
151
  selected_block = self.consumption_block
175
-
176
- # Execute the selected sub-block and get the result
177
- result = await selected_block.forward(step, context) # type: ignore
178
-
152
+ result = await selected_block.forward(step, context) # type: ignore
179
153
  return result
180
154
 
181
- # @trigger_class()
182
155
  class MonthPlanBlock(Block):
183
156
  """Monthly Planning"""
184
157
  def __init__(self, llm: LLM, memory: Memory, simulator: Simulator, economy_client: EconomyClient):
185
- super().__init__("MonthPlanBlock", llm, memory, simulator)
158
+ super().__init__("MonthPlanBlock", llm=llm, memory=memory, simulator=simulator)
186
159
  self.economy_client = economy_client
187
160
  self.llm_error = 0
188
161
  self.last_time_trigger = None
@@ -198,26 +171,16 @@ class MonthPlanBlock(Block):
198
171
 
199
172
  async def forward(self):
200
173
  if await self.month_trigger():
201
- # while True:
202
- # if self.forward_times == 0:
203
- # break
204
- # firm_forward = await self.memory.get('firm_forward')
205
- # bank_forward = await self.memory.get('bank_forward')
206
- # nbs_forward = await self.memory.get('nbs_forward')
207
- # government_forward = await self.memory.get('government_forward')
208
- # if self.forward_times <= firm_forward and self.forward_times <= bank_forward and self.forward_times <= nbs_forward and self.forward_times <= government_forward:
209
- # break
210
- # await asyncio.sleep(1)
211
- agent_id = await self.memory.get("id")
212
- firm_id = await self.memory.get('firm_id')
213
- bank_id = await self.memory.get('bank_id')
214
- name = await self.memory.get('name')
215
- age = await self.memory.get('age')
216
- city = await self.memory.get('city')
217
- job = await self.memory.get('occupation')
218
- skill = await self.memory.get('work_skill')
219
- consumption = await self.memory.get('consumption_currency')
220
- tax_paid = await self.memory.get('tax_paid')
174
+ agent_id = await self.memory.status.get("id")
175
+ firm_id = await self.memory.status.get('firm_id')
176
+ bank_id = await self.memory.status.get('bank_id')
177
+ name = await self.memory.status.get('name')
178
+ age = await self.memory.status.get('age')
179
+ city = await self.memory.status.get('city')
180
+ 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')
183
+ tax_paid = await self.memory.status.get('tax_paid')
221
184
  price = await self.economy_client.get(firm_id, 'price')
222
185
  wealth = await self.economy_client.get(agent_id, 'currency')
223
186
  interest_rate = await self.economy_client.get(bank_id, 'interest_rate')
@@ -228,7 +191,7 @@ class MonthPlanBlock(Block):
228
191
  job_prompt = f'''
229
192
  In the previous month, you worked as a(an) {job}. If you continue working this month, your expected hourly income will be ${skill:.2f}.
230
193
  '''
231
- consumption_propensity = await self.memory.get('consumption_propensity')
194
+ consumption_propensity = await self.memory.status.get('consumption_propensity')
232
195
  if (consumption <= 0) and (consumption_propensity > 0):
233
196
  consumption_prompt = f'''
234
197
  Besides, you had no consumption due to shortage of goods.
@@ -238,7 +201,7 @@ class MonthPlanBlock(Block):
238
201
  Besides, your consumption was ${consumption:.2f}.
239
202
  '''
240
203
  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.'''
241
- if UBI:
204
+ if UBI and self.forward_times >= 96:
242
205
  tax_prompt = f'{tax_prompt} Specifically, the government directly provides ${UBI} per capita in each month.'
243
206
  price_prompt = f'''Meanwhile, in the consumption market, the average price of essential goods is now at ${price:.2f}.'''
244
207
  job_prompt = prettify_document(job_prompt)
@@ -254,41 +217,42 @@ class MonthPlanBlock(Block):
254
217
  Any other output words are NOT allowed.
255
218
  '''
256
219
  obs_prompt = prettify_document(obs_prompt)
257
- await self.memory.update('dialog_queue', [{'role': 'user', 'content': obs_prompt}], mode='merge')
258
- dialog_queue = await self.memory.get('dialog_queue')
220
+ await self.memory.status.update('dialog_queue', [{'role': 'user', 'content': obs_prompt}], mode='merge')
221
+ dialog_queue = await self.memory.status.get('dialog_queue')
259
222
  content = await self.llm.atext_request(list(dialog_queue), timeout=300)
260
- await self.memory.update('dialog_queue', [{'role': 'assistant', 'content': content}], mode='merge')
223
+ await self.memory.status.update('dialog_queue', [{'role': 'assistant', 'content': content}], mode='merge')
261
224
  try:
262
225
  propensity_dict = extract_dict_from_string(content)[0]
263
226
  work_propensity, consumption_propensity = propensity_dict['work'], propensity_dict['consumption']
264
227
  if isinstance(work_propensity, numbers.Number) and isinstance(consumption_propensity, numbers.Number):
265
- await self.memory.update('work_propensity', work_propensity)
266
- await self.memory.update('consumption_propensity', consumption_propensity)
228
+ await self.memory.status.update('work_propensity', work_propensity)
229
+ await self.memory.status.update('consumption_propensity', consumption_propensity)
267
230
  else:
268
231
  self.llm_error += 1
269
232
  except:
270
233
  self.llm_error += 1
271
234
 
272
- skill = await self.memory.get('work_skill')
273
- work_propensity = await self.memory.get('work_propensity')
274
- consumption_propensity = await self.memory.get('consumption_propensity')
235
+ skill = await self.memory.status.get('work_skill')
236
+ work_propensity = await self.memory.status.get('work_propensity')
237
+ consumption_propensity = await self.memory.status.get('consumption_propensity')
275
238
  work_hours = work_propensity * num_labor_hours
276
- await self.memory.update('income_currency', work_hours * skill)
239
+ await self.memory.status.update('income_currency', work_hours * skill)
277
240
  wealth = await self.economy_client.get(agent_id, 'currency')
278
241
  await self.economy_client.update(agent_id, 'currency', wealth + work_hours * skill)
279
242
  await self.economy_client.add_delta_value(firm_id, 'inventory', int(work_hours*productivity_per_labor))
280
243
 
281
- income_currency = await self.memory.get('income_currency')
282
- await self.memory.update('income_currency', income_currency + UBI)
283
- wealth = await self.economy_client.get(agent_id, 'currency')
284
- await self.economy_client.update(agent_id, 'currency', wealth + UBI)
244
+ 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)
285
249
 
286
250
  wealth = await self.economy_client.get(agent_id, 'currency')
287
- await self.memory.update('to_consumption_currency', consumption_propensity*wealth)
251
+ await self.memory.status.update('to_consumption_currency', consumption_propensity*wealth)
288
252
 
289
- await self.memory.update('consumption_currency', 0)
290
- await self.memory.update('goods_demand', 0)
291
- await self.memory.update('goods_consumption', 0)
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)
292
256
 
293
257
  if self.forward_times % 3 == 0:
294
258
  obs_prompt = f'''
@@ -335,11 +299,11 @@ class MonthPlanBlock(Block):
335
299
  else:
336
300
  content[k] = category2score[content[k].lower()]
337
301
  depression = sum(list(content.values()))
338
- await self.memory.update('depression', depression)
302
+ await self.memory.status.update('depression', depression)
339
303
  except:
340
304
  self.llm_error += 1
341
305
 
342
- if UBI and self.forward_times % 12:
306
+ if UBI and self.forward_times >= 96 and self.forward_times % 12:
343
307
  obs_prompt = f'''
344
308
  {problem_prompt} {job_prompt} {consumption_prompt} {tax_prompt} {price_prompt}
345
309
  Your current savings account balance is ${wealth:.2f}. Interest rates, as set by your bank, stand at {interest_rate*100:.2f}%.
@@ -347,10 +311,7 @@ class MonthPlanBlock(Block):
347
311
  '''
348
312
  obs_prompt = prettify_document(obs_prompt)
349
313
  content = await self.llm.atext_request([{'role': 'user', 'content': obs_prompt}], timeout=300)
350
- await self.memory.update('ubi_opinion', [content], mode='merge')
351
- ubi_opinion = await self.memory.get('ubi_opinion')
352
- with open(f'/data1/linian/SocietySim/socialcity-agent-zoo/ubi_opinions/{agent_id}.pkl', 'wb') as f:
353
- pkl.dump(ubi_opinion, f)
314
+ await self.memory.status.update('ubi_opinion', [content], mode='merge')
354
315
 
355
316
  self.forward_times += 1
356
- await self.memory.update('forward', self.forward_times)
317
+ await self.memory.status.update('forward', self.forward_times)
@@ -1,8 +1,8 @@
1
1
  from typing import List
2
2
  from .dispatcher import BlockDispatcher
3
3
  from pycityagent.environment.simulator import Simulator
4
- from pycityagent.llm.llm import LLM
5
- from pycityagent.memory.memory import Memory
4
+ from pycityagent.llm import LLM
5
+ from pycityagent.memory import Memory
6
6
  from pycityagent.workflow.block import Block
7
7
  import random
8
8
  import logging
@@ -31,25 +31,32 @@ User requirement: {intention}
31
31
  Your output must be a single selection from ['home', 'workplace', 'other'] without any additional text or explanation.
32
32
  """
33
33
 
34
+ RADIUS_PROMPT = """As an intelligent decision system, please determine the maximum travel radius (in meters) based on the current emotional state.
35
+
36
+ Your current emotion: {emotion_types}
37
+ Your current thought: {thought}
38
+
39
+ Please analyze how these emotions would affect travel willingness and return only a single integer number between 1000-100000 representing the maximum travel radius in meters. A more positive emotional state generally leads to greater willingness to travel further.
40
+
41
+ Return only the integer number without any additional text or explanation."""
42
+
34
43
  class PlaceSelectionBlock(Block):
35
44
  """
36
45
  选择目的地
37
46
  PlaceSelectionBlock
38
47
  """
39
- configurable_fields: List[str] = ["search_radius", "search_limit"]
48
+ configurable_fields: List[str] = ["search_limit"]
40
49
  default_values = {
41
- "search_radius": 100000,
42
50
  "search_limit": 10
43
51
  }
44
52
 
45
53
  def __init__(self, llm: LLM, memory: Memory, simulator: Simulator):
46
- super().__init__("PlaceSelectionBlock", llm, memory, simulator)
54
+ super().__init__("PlaceSelectionBlock", llm=llm, memory=memory, simulator=simulator)
47
55
  self.description = "Used to select and determine destinations for unknown locations (excluding home and workplace), such as choosing specific shopping malls, restaurants and other places"
48
56
  self.typeSelectionPrompt = FormatPrompt(PLACE_TYPE_SELECTION_PROMPT)
49
57
  self.secondTypeSelectionPrompt = FormatPrompt(PLACE_SECOND_TYPE_SELECTION_PROMPT)
50
-
58
+ self.radiusPrompt = FormatPrompt(RADIUS_PROMPT)
51
59
  # configurable fields
52
- self.search_radius = 100000
53
60
  self.search_limit = 10
54
61
 
55
62
  async def forward(self, step, context):
@@ -71,13 +78,18 @@ class PlaceSelectionBlock(Block):
71
78
  poi_category = sub_category
72
79
  )
73
80
  levelTwoType = await self.llm.atext_request(self.secondTypeSelectionPrompt.to_dialog()) # type: ignore
74
- center = await self.memory.get('position')
81
+ center = await self.memory.status.get('position')
75
82
  center = (center['xy_position']['x'], center['xy_position']['y'])
83
+ self.radiusPrompt.format(
84
+ emotion_types=await self.memory.status.get("emotion_types"),
85
+ thought=await self.memory.status.get("thought")
86
+ )
87
+ radius = int(await self.llm.atext_request(self.radiusPrompt.to_dialog())) # type: ignore
76
88
  try:
77
89
  pois = self.simulator.map.query_pois(
78
90
  center = center,
79
91
  category_prefix = levelTwoType,
80
- radius=self.search_radius,
92
+ radius=radius,
81
93
  limit=self.search_limit
82
94
  )
83
95
  except Exception as e:
@@ -86,7 +98,7 @@ class PlaceSelectionBlock(Block):
86
98
  pois = self.simulator.map.query_pois(
87
99
  center = center,
88
100
  category_prefix = levelTwoType,
89
- radius=self.search_radius,
101
+ radius=radius,
90
102
  limit=self.search_limit
91
103
  )
92
104
  if len(pois) > 0:
@@ -94,11 +106,12 @@ class PlaceSelectionBlock(Block):
94
106
  nextPlace = (poi['name'], poi['aoi_id'])
95
107
  # 将地点信息保存到context中
96
108
  context['next_place'] = nextPlace
97
- # 这里应该添加选择地点的具体逻辑
109
+ node_id = await self.memory.stream.add_mobility(description=f"For {step['intention']}, I selected the destination: {nextPlace}")
98
110
  return {
99
111
  'success': True,
100
112
  'evaluation': f'Successfully selected the destination: {nextPlace}',
101
- 'consumed_time': 5
113
+ 'consumed_time': 5,
114
+ 'node_id': node_id
102
115
  }
103
116
  else:
104
117
  simmap = self.simulator.map
@@ -106,11 +119,12 @@ class PlaceSelectionBlock(Block):
106
119
  nextPlace = (poi['name'], poi['aoi_id'])
107
120
  # 将地点信息保存到context中
108
121
  context['next_place'] = nextPlace
109
- # 这里应该添加选择地点的具体逻辑
122
+ node_id = await self.memory.stream.add_mobility(description=f"For {step['intention']}, I selected the destination: {nextPlace}")
110
123
  return {
111
124
  'success': True,
112
125
  'evaluation': f'Successfully selected the destination: {nextPlace}',
113
- 'consumed_time': 5
126
+ 'consumed_time': 5,
127
+ 'node_id': node_id
114
128
  }
115
129
 
116
130
  class MoveBlock(Block):
@@ -119,30 +133,35 @@ class MoveBlock(Block):
119
133
  MoveBlock
120
134
  """
121
135
  def __init__(self, llm: LLM, memory: Memory, simulator: Simulator):
122
- super().__init__("MoveBlock", llm, memory, simulator)
136
+ super().__init__("MoveBlock", llm=llm, memory=memory, simulator=simulator)
123
137
  self.description = "Used to execute specific mobility operations, such as returning home, going to work, or visiting a specific location"
124
138
  self.placeAnalysisPrompt = FormatPrompt(PLACE_ANALYSIS_PROMPT)
125
139
 
126
140
  async def forward(self, step, context):
127
141
  # 这里应该添加移动的具体逻辑
128
- agent_id = await self.memory.get("id")
142
+ agent_id = await self.memory.status.get("id")
129
143
  self.placeAnalysisPrompt.format(
130
144
  plan = context['plan'],
131
145
  intention = step["intention"]
132
146
  )
147
+ number_poi_visited = await self.memory.status.get("number_poi_visited")
148
+ number_poi_visited += 1
149
+ await self.memory.status.update("number_poi_visited", number_poi_visited)
133
150
  response = await self.llm.atext_request(self.placeAnalysisPrompt.to_dialog()) # type: ignore
134
151
  if response == 'home':
135
152
  # 返回到家
136
- home = await self.memory.get('home')
153
+ home = await self.memory.status.get('home')
137
154
  home = home['aoi_position']['aoi_id']
138
- nowPlace = await self.memory.get('position')
155
+ nowPlace = await self.memory.status.get('position')
156
+ node_id = await self.memory.stream.add_mobility(description=f"I returned home")
139
157
  if 'aoi_position' in nowPlace and nowPlace['aoi_position']['aoi_id'] == home:
140
158
  return {
141
159
  'success': True,
142
160
  'evaluation': f'Successfully returned home (already at home)',
143
161
  'from_place': home,
144
162
  'to_place': home,
145
- 'consumed_time': 0
163
+ 'consumed_time': 0,
164
+ 'node_id': node_id
146
165
  }
147
166
  await self.simulator.set_aoi_schedules(
148
167
  person_id=agent_id,
@@ -153,20 +172,23 @@ class MoveBlock(Block):
153
172
  'evaluation': f'Successfully returned home',
154
173
  'from_place': nowPlace['aoi_position']['aoi_id'],
155
174
  'to_place': home,
156
- 'consumed_time': 45
175
+ 'consumed_time': 45,
176
+ 'node_id': node_id
157
177
  }
158
178
  elif response == 'workplace':
159
179
  # 返回到工作地点
160
- work = await self.memory.get('work')
180
+ work = await self.memory.status.get('work')
161
181
  work = work['aoi_position']['aoi_id']
162
- nowPlace = await self.memory.get('position')
182
+ nowPlace = await self.memory.status.get('position')
183
+ node_id = await self.memory.stream.add_mobility(description=f"I went to my workplace")
163
184
  if 'aoi_position' in nowPlace and nowPlace['aoi_position']['aoi_id'] == work:
164
185
  return {
165
186
  'success': True,
166
187
  'evaluation': f'Successfully reached the workplace (already at the workplace)',
167
188
  'from_place': work,
168
189
  'to_place': work,
169
- 'consumed_time': 0
190
+ 'consumed_time': 0,
191
+ 'node_id': node_id
170
192
  }
171
193
  await self.simulator.set_aoi_schedules(
172
194
  person_id=agent_id,
@@ -177,12 +199,14 @@ class MoveBlock(Block):
177
199
  'evaluation': f'Successfully reached the workplace',
178
200
  'from_place': nowPlace['aoi_position']['aoi_id'],
179
201
  'to_place': work,
180
- 'consumed_time': 45
202
+ 'consumed_time': 45,
203
+ 'node_id': node_id
181
204
  }
182
205
  else:
183
206
  # 移动到其他地点
184
207
  next_place = context.get('next_place', None)
185
- nowPlace = await self.memory.get('position')
208
+ nowPlace = await self.memory.status.get('position')
209
+ node_id = await self.memory.stream.add_mobility(description=f"I went to {next_place}")
186
210
  if next_place != None:
187
211
  await self.simulator.set_aoi_schedules(
188
212
  person_id=agent_id,
@@ -205,7 +229,8 @@ class MoveBlock(Block):
205
229
  'evaluation': f'Successfully reached the destination: {next_place}',
206
230
  'from_place': nowPlace['aoi_position']['aoi_id'],
207
231
  'to_place': next_place[1],
208
- 'consumed_time': 45
232
+ 'consumed_time': 45,
233
+ 'node_id': node_id
209
234
  }
210
235
 
211
236
  class MobilityNoneBlock(Block):
@@ -214,14 +239,16 @@ class MobilityNoneBlock(Block):
214
239
  MobilityNoneBlock
215
240
  """
216
241
  def __init__(self, llm: LLM, memory: Memory):
217
- super().__init__("MobilityNoneBlock", llm, memory)
242
+ super().__init__("MobilityNoneBlock", llm=llm, memory=memory)
218
243
  self.description = "Used to handle other cases"
219
244
 
220
245
  async def forward(self, step, context):
246
+ node_id = await self.memory.stream.add_mobility(description=f"I finished {step['intention']}")
221
247
  return {
222
248
  'success': True,
223
249
  'evaluation': f'Finished executing {step["intention"]}',
224
- 'consumed_time': 0
250
+ 'consumed_time': 0,
251
+ 'node_id': node_id
225
252
  }
226
253
 
227
254
  class MobilityBlock(Block):
@@ -230,7 +257,7 @@ class MobilityBlock(Block):
230
257
  mobility_none_block: MobilityNoneBlock
231
258
 
232
259
  def __init__(self, llm: LLM, memory: Memory, simulator: Simulator):
233
- super().__init__("MobilityBlock", llm, memory, simulator)
260
+ super().__init__("MobilityBlock", llm=llm, memory=memory, simulator=simulator)
234
261
  # 初始化所有块
235
262
  self.place_selection_block = PlaceSelectionBlock(llm, memory, simulator)
236
263
  self.move_block = MoveBlock(llm, memory, simulator)