pycityagent 2.0.0a65__cp39-cp39-macosx_11_0_arm64.whl → 2.0.0a67__cp39-cp39-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,13 +1,19 @@
1
+ import math
1
2
  from typing import List
2
- from .dispatcher import BlockDispatcher
3
+
3
4
  from pycityagent.environment.simulator import Simulator
4
5
  from pycityagent.llm import LLM
5
6
  from pycityagent.memory import Memory
6
7
  from pycityagent.workflow.block import Block
8
+ import numpy as np
9
+ from operator import itemgetter
7
10
  import random
8
11
  import logging
9
- logger = logging.getLogger("pycityagent")
10
12
  from pycityagent.workflow.prompt import FormatPrompt
13
+ from .dispatcher import BlockDispatcher
14
+
15
+ logger = logging.getLogger("pycityagent")
16
+
11
17
 
12
18
  PLACE_TYPE_SELECTION_PROMPT = """
13
19
  As an intelligent decision system, please determine the type of place the user needs to visit based on their input requirement.
@@ -38,36 +44,104 @@ Current temperature: {temperature}
38
44
  Your current emotion: {emotion_types}
39
45
  Your current thought: {thought}
40
46
 
41
- 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.
47
+ Please analyze how these emotions would affect travel willingness and return only a single integer number between 3000-100000 representing the maximum travel radius in meters. A more positive emotional state generally leads to greater willingness to travel further.
42
48
 
43
49
  Return only the integer number without any additional text or explanation."""
44
50
 
51
+
52
+ def gravity_model(pois):
53
+ N = len(pois)
54
+ pois_Dis = {
55
+ "1k": [],
56
+ "2k": [],
57
+ "3k": [],
58
+ "4k": [],
59
+ "5k": [],
60
+ "6k": [],
61
+ "7k": [],
62
+ "8k": [],
63
+ "9k": [],
64
+ "10k": [],
65
+ "more": [],
66
+ }
67
+ for poi in pois:
68
+ iflt10k = True
69
+ for d in range(1, 11):
70
+ if (d - 1) * 1000 <= poi[1] < d * 1000:
71
+ pois_Dis["{}k".format(d)].append(poi)
72
+ iflt10k = False
73
+ break
74
+ if iflt10k:
75
+ pois_Dis["more"].append(poi)
76
+
77
+ res = []
78
+ distanceProb = []
79
+ for poi in pois:
80
+ iflt10k = True
81
+ for d in range(1, 11):
82
+ if (d - 1) * 1000 <= poi[1] < d * 1000:
83
+ n = len(pois_Dis["{}k".format(d)])
84
+ S = math.pi * ((d * 1000) ** 2 - ((d - 1) * 1000) ** 2)
85
+ density = n / S
86
+ distance = poi[1]
87
+ distance = distance if distance > 1 else 1
88
+
89
+ # distance decay coefficient, use the square of distance to calculate, so that distant places are less likely to be selected
90
+ weight = density / (distance**2) # the original weight is reasonable
91
+ res.append((poi[0]["name"], poi[0]["id"], weight, distance))
92
+ distanceProb.append(1 / (math.sqrt(distance)))
93
+ iflt10k = False
94
+ break
95
+
96
+ distanceProb = np.array(distanceProb)
97
+ distanceProb = distanceProb / np.sum(distanceProb)
98
+ distanceProb = list(distanceProb)
99
+
100
+ options = list(range(len(res)))
101
+ sample = list(
102
+ np.random.choice(options, size=50, p=distanceProb)
103
+ ) # sample based on the probability value
104
+
105
+ get_elements = itemgetter(*sample)
106
+ random_elements = get_elements(res)
107
+
108
+ # normalize the weight to become the true probability value
109
+ weightSum = sum(item[2] for item in random_elements)
110
+ final = [
111
+ (item[0], item[1], item[2] / weightSum, item[3]) for item in random_elements
112
+ ]
113
+ return final
114
+
115
+
45
116
  class PlaceSelectionBlock(Block):
46
117
  """
47
- 选择目的地
118
+ Select destination
48
119
  PlaceSelectionBlock
49
120
  """
121
+
50
122
  configurable_fields: List[str] = ["search_limit"]
51
- default_values = {
52
- "search_limit": 10
53
- }
123
+ default_values = {"search_limit": 10000}
54
124
 
55
125
  def __init__(self, llm: LLM, memory: Memory, simulator: Simulator):
56
- super().__init__("PlaceSelectionBlock", llm=llm, memory=memory, simulator=simulator)
126
+ super().__init__(
127
+ "PlaceSelectionBlock", llm=llm, memory=memory, simulator=simulator
128
+ )
57
129
  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"
58
130
  self.typeSelectionPrompt = FormatPrompt(PLACE_TYPE_SELECTION_PROMPT)
59
- self.secondTypeSelectionPrompt = FormatPrompt(PLACE_SECOND_TYPE_SELECTION_PROMPT)
131
+ self.secondTypeSelectionPrompt = FormatPrompt(
132
+ PLACE_SECOND_TYPE_SELECTION_PROMPT
133
+ )
60
134
  self.radiusPrompt = FormatPrompt(RADIUS_PROMPT)
61
135
  # configurable fields
62
- self.search_limit = 10
136
+ self.search_limit = 10000
63
137
 
64
138
  async def forward(self, step, context):
65
139
  self.typeSelectionPrompt.format(
66
- plan = context['plan'],
67
- intention = step['intention'],
68
- poi_category = list(self.simulator.poi_cate.keys())
140
+ plan=context["plan"],
141
+ intention=step["intention"],
142
+ poi_category=list(self.simulator.poi_cate.keys()),
69
143
  )
70
- levelOneType = await self.llm.atext_request(self.typeSelectionPrompt.to_dialog()) # type: ignore
144
+ levelOneType = await self.llm.atext_request(self.typeSelectionPrompt.to_dialog()) # type: ignore
71
145
  try:
72
146
  sub_category = self.simulator.poi_cate[levelOneType]
73
147
  except Exception as e:
@@ -75,67 +149,77 @@ class PlaceSelectionBlock(Block):
75
149
  levelOneType = random.choice(list(self.simulator.poi_cate.keys()))
76
150
  sub_category = self.simulator.poi_cate[levelOneType]
77
151
  self.secondTypeSelectionPrompt.format(
78
- plan = context['plan'],
79
- intention = step['intention'],
80
- poi_category = sub_category
152
+ plan=context["plan"], intention=step["intention"], poi_category=sub_category
81
153
  )
82
- levelTwoType = await self.llm.atext_request(self.secondTypeSelectionPrompt.to_dialog()) # type: ignore
83
- center = await self.memory.status.get('position')
84
- center = (center['xy_position']['x'], center['xy_position']['y'])
154
+ levelTwoType = await self.llm.atext_request(self.secondTypeSelectionPrompt.to_dialog()) # type: ignore
155
+ center = await self.memory.status.get("position")
156
+ center = (center["xy_position"]["x"], center["xy_position"]["y"])
85
157
  self.radiusPrompt.format(
86
158
  emotion_types=await self.memory.status.get("emotion_types"),
87
159
  thought=await self.memory.status.get("thought"),
88
160
  weather=self.simulator.sence("weather"),
89
- temperature=self.simulator.sence("temperature")
161
+ temperature=self.simulator.sence("temperature"),
90
162
  )
91
- radius = int(await self.llm.atext_request(self.radiusPrompt.to_dialog())) # type: ignore
163
+ radius = int(await self.llm.atext_request(self.radiusPrompt.to_dialog())) # type: ignore
92
164
  try:
93
165
  pois = self.simulator.map.query_pois(
94
- center = center,
95
- category_prefix = levelTwoType,
166
+ center=center,
167
+ category_prefix=levelTwoType,
96
168
  radius=radius,
97
- limit=self.search_limit
169
+ limit=self.search_limit,
98
170
  )
99
171
  except Exception as e:
100
172
  logger.warning(f"Error querying pois: {e}")
101
173
  levelTwoType = random.choice(sub_category)
102
174
  pois = self.simulator.map.query_pois(
103
- center = center,
104
- category_prefix = levelTwoType,
175
+ center=center,
176
+ category_prefix=levelTwoType,
105
177
  radius=radius,
106
- limit=self.search_limit
178
+ limit=self.search_limit,
107
179
  )
108
180
  if len(pois) > 0:
109
- poi = random.choice(pois)[0]
110
- nextPlace = (poi['name'], poi['aoi_id'])
111
- # 将地点信息保存到context中
112
- context['next_place'] = nextPlace
113
- node_id = await self.memory.stream.add_mobility(description=f"For {step['intention']}, I selected the destination: {nextPlace}")
181
+ pois = gravity_model(pois)
182
+ probabilities = [item[2] for item in pois]
183
+ options = list(range(len(pois)))
184
+ sample = np.random.choice(
185
+ options, size=1, p=probabilities
186
+ ) # sample based on the probability value
187
+ nextPlace = pois[sample[0]]
188
+ nextPlace = (nextPlace[0], nextPlace[1])
189
+ # save the destination to context
190
+ context["next_place"] = nextPlace
191
+ node_id = await self.memory.stream.add_mobility(
192
+ description=f"For {step['intention']}, I selected the destination: {nextPlace}"
193
+ )
114
194
  return {
115
- 'success': True,
116
- 'evaluation': f'Successfully selected the destination: {nextPlace}',
117
- 'consumed_time': 5,
118
- 'node_id': node_id
195
+ "success": True,
196
+ "evaluation": f"Successfully selected the destination: {nextPlace}",
197
+ "consumed_time": 5,
198
+ "node_id": node_id,
119
199
  }
120
200
  else:
121
201
  simmap = self.simulator.map
122
202
  poi = random.choice(list(simmap.pois.values()))
123
- nextPlace = (poi['name'], poi['aoi_id'])
124
- # 将地点信息保存到context
125
- context['next_place'] = nextPlace
126
- node_id = await self.memory.stream.add_mobility(description=f"For {step['intention']}, I selected the destination: {nextPlace}")
203
+ nextPlace = (poi["name"], poi["aoi_id"])
204
+ # save the destination to context
205
+ context["next_place"] = nextPlace
206
+ node_id = await self.memory.stream.add_mobility(
207
+ description=f"For {step['intention']}, I selected the destination: {nextPlace}"
208
+ )
127
209
  return {
128
- 'success': True,
129
- 'evaluation': f'Successfully selected the destination: {nextPlace}',
130
- 'consumed_time': 5,
131
- 'node_id': node_id
210
+ "success": True,
211
+ "evaluation": f"Successfully selected the destination: {nextPlace}",
212
+ "consumed_time": 5,
213
+ "node_id": node_id,
132
214
  }
133
215
 
216
+
134
217
  class MoveBlock(Block):
135
218
  """
136
- 移动操作
219
+ Execute mobility operations
137
220
  MoveBlock
138
221
  """
222
+
139
223
  def __init__(self, llm: LLM, memory: Memory, simulator: Simulator):
140
224
  super().__init__("MoveBlock", llm=llm, memory=memory, simulator=simulator)
141
225
  self.description = "Used to execute specific mobility operations, such as returning home, going to work, or visiting a specific location"
@@ -145,68 +229,79 @@ class MoveBlock(Block):
145
229
  # 这里应该添加移动的具体逻辑
146
230
  agent_id = await self.memory.status.get("id")
147
231
  self.placeAnalysisPrompt.format(
148
- plan = context['plan'],
149
- intention = step["intention"]
232
+ plan=context["plan"], intention=step["intention"]
150
233
  )
151
234
  number_poi_visited = await self.memory.status.get("number_poi_visited")
152
235
  number_poi_visited += 1
153
236
  await self.memory.status.update("number_poi_visited", number_poi_visited)
154
- response = await self.llm.atext_request(self.placeAnalysisPrompt.to_dialog()) # type: ignore
155
- if response == 'home':
237
+ response = await self.llm.atext_request(self.placeAnalysisPrompt.to_dialog()) # type: ignore
238
+ if response == "home":
156
239
  # 返回到家
157
- home = await self.memory.status.get('home')
158
- home = home['aoi_position']['aoi_id']
159
- nowPlace = await self.memory.status.get('position')
160
- node_id = await self.memory.stream.add_mobility(description=f"I returned home")
161
- if 'aoi_position' in nowPlace and nowPlace['aoi_position']['aoi_id'] == home:
240
+ home = await self.memory.status.get("home")
241
+ home = home["aoi_position"]["aoi_id"]
242
+ nowPlace = await self.memory.status.get("position")
243
+ node_id = await self.memory.stream.add_mobility(
244
+ description=f"I returned home"
245
+ )
246
+ if (
247
+ "aoi_position" in nowPlace
248
+ and nowPlace["aoi_position"]["aoi_id"] == home
249
+ ):
162
250
  return {
163
- 'success': True,
164
- 'evaluation': f'Successfully returned home (already at home)',
165
- 'to_place': home,
166
- 'consumed_time': 0,
167
- 'node_id': node_id
251
+ "success": True,
252
+ "evaluation": f"Successfully returned home (already at home)",
253
+ "to_place": home,
254
+ "consumed_time": 0,
255
+ "node_id": node_id,
168
256
  }
169
257
  await self.simulator.set_aoi_schedules(
170
258
  person_id=agent_id,
171
259
  target_positions=home,
172
260
  )
173
261
  return {
174
- 'success': True,
175
- 'evaluation': f'Successfully returned home',
176
- 'to_place': home,
177
- 'consumed_time': 45,
178
- 'node_id': node_id
262
+ "success": True,
263
+ "evaluation": f"Successfully returned home",
264
+ "to_place": home,
265
+ "consumed_time": 45,
266
+ "node_id": node_id,
179
267
  }
180
- elif response == 'workplace':
268
+ elif response == "workplace":
181
269
  # 返回到工作地点
182
- work = await self.memory.status.get('work')
183
- work = work['aoi_position']['aoi_id']
184
- nowPlace = await self.memory.status.get('position')
185
- node_id = await self.memory.stream.add_mobility(description=f"I went to my workplace")
186
- if 'aoi_position' in nowPlace and nowPlace['aoi_position']['aoi_id'] == work:
270
+ work = await self.memory.status.get("work")
271
+ work = work["aoi_position"]["aoi_id"]
272
+ nowPlace = await self.memory.status.get("position")
273
+ node_id = await self.memory.stream.add_mobility(
274
+ description=f"I went to my workplace"
275
+ )
276
+ if (
277
+ "aoi_position" in nowPlace
278
+ and nowPlace["aoi_position"]["aoi_id"] == work
279
+ ):
187
280
  return {
188
- 'success': True,
189
- 'evaluation': f'Successfully reached the workplace (already at the workplace)',
190
- 'to_place': work,
191
- 'consumed_time': 0,
192
- 'node_id': node_id
281
+ "success": True,
282
+ "evaluation": f"Successfully reached the workplace (already at the workplace)",
283
+ "to_place": work,
284
+ "consumed_time": 0,
285
+ "node_id": node_id,
193
286
  }
194
287
  await self.simulator.set_aoi_schedules(
195
288
  person_id=agent_id,
196
289
  target_positions=work,
197
290
  )
198
291
  return {
199
- 'success': True,
200
- 'evaluation': f'Successfully reached the workplace',
201
- 'to_place': work,
202
- 'consumed_time': 45,
203
- 'node_id': node_id
292
+ "success": True,
293
+ "evaluation": f"Successfully reached the workplace",
294
+ "to_place": work,
295
+ "consumed_time": 45,
296
+ "node_id": node_id,
204
297
  }
205
298
  else:
206
299
  # 移动到其他地点
207
- next_place = context.get('next_place', None)
208
- nowPlace = await self.memory.status.get('position')
209
- node_id = await self.memory.stream.add_mobility(description=f"I went to {next_place}")
300
+ next_place = context.get("next_place", None)
301
+ nowPlace = await self.memory.status.get("position")
302
+ node_id = await self.memory.stream.add_mobility(
303
+ description=f"I went to {next_place}"
304
+ )
210
305
  if next_place != None:
211
306
  await self.simulator.set_aoi_schedules(
212
307
  person_id=agent_id,
@@ -215,41 +310,46 @@ class MoveBlock(Block):
215
310
  else:
216
311
  while True:
217
312
  r_aoi = random.choice(list(self.simulator.map.aois.values()))
218
- if len(r_aoi['poi_ids']) > 0:
219
- r_poi = random.choice(r_aoi['poi_ids'])
313
+ if len(r_aoi["poi_ids"]) > 0:
314
+ r_poi = random.choice(r_aoi["poi_ids"])
220
315
  break
221
316
  poi = self.simulator.map.pois[r_poi]
222
- next_place = (poi['name'], poi['aoi_id'])
317
+ next_place = (poi["name"], poi["aoi_id"])
223
318
  await self.simulator.set_aoi_schedules(
224
319
  person_id=agent_id,
225
320
  target_positions=next_place[1],
226
321
  )
227
322
  return {
228
- 'success': True,
229
- 'evaluation': f'Successfully reached the destination: {next_place}',
230
- 'to_place': next_place[1],
231
- 'consumed_time': 45,
232
- 'node_id': node_id
323
+ "success": True,
324
+ "evaluation": f"Successfully reached the destination: {next_place}",
325
+ "to_place": next_place[1],
326
+ "consumed_time": 45,
327
+ "node_id": node_id,
233
328
  }
234
-
329
+
330
+
235
331
  class MobilityNoneBlock(Block):
236
332
  """
237
333
  空操作
238
334
  MobilityNoneBlock
239
335
  """
336
+
240
337
  def __init__(self, llm: LLM, memory: Memory):
241
338
  super().__init__("MobilityNoneBlock", llm=llm, memory=memory)
242
339
  self.description = "Used to handle other cases"
243
340
 
244
341
  async def forward(self, step, context):
245
- node_id = await self.memory.stream.add_mobility(description=f"I finished {step['intention']}")
342
+ node_id = await self.memory.stream.add_mobility(
343
+ description=f"I finished {step['intention']}"
344
+ )
246
345
  return {
247
- 'success': True,
248
- 'evaluation': f'Finished executing {step["intention"]}',
249
- 'consumed_time': 0,
250
- 'node_id': node_id
346
+ "success": True,
347
+ "evaluation": f'Finished executing {step["intention"]}',
348
+ "consumed_time": 0,
349
+ "node_id": node_id,
251
350
  }
252
351
 
352
+
253
353
  class MobilityBlock(Block):
254
354
  place_selection_block: PlaceSelectionBlock
255
355
  move_block: MoveBlock
@@ -266,19 +366,23 @@ class MobilityBlock(Block):
266
366
  # 初始化调度器
267
367
  self.dispatcher = BlockDispatcher(llm)
268
368
  # 注册所有块
269
- self.dispatcher.register_blocks([self.place_selection_block, self.move_block, self.mobility_none_block])
369
+ self.dispatcher.register_blocks(
370
+ [self.place_selection_block, self.move_block, self.mobility_none_block]
371
+ )
270
372
 
271
- async def forward(self, step, context):
373
+ async def forward(self, step, context):
272
374
  self.trigger_time += 1
273
- consumption_start = self.llm.prompt_tokens_used + self.llm.completion_tokens_used
375
+ consumption_start = (
376
+ self.llm.prompt_tokens_used + self.llm.completion_tokens_used
377
+ )
274
378
 
275
379
  # Select the appropriate sub-block using dispatcher
276
380
  selected_block = await self.dispatcher.dispatch(step)
277
-
381
+
278
382
  # Execute the selected sub-block and get the result
279
- result = await selected_block.forward(step, context) # type: ignore
383
+ result = await selected_block.forward(step, context) # type: ignore
280
384
 
281
385
  consumption_end = self.llm.prompt_tokens_used + self.llm.completion_tokens_used
282
386
  self.token_consumption += consumption_end - consumption_start
283
-
284
- return result
387
+
388
+ return result