pycityagent 2.0.0a48__cp312-cp312-macosx_11_0_arm64.whl → 2.0.0a49__cp312-cp312-macosx_11_0_arm64.whl

Sign up to get free protection for your applications and to get access to all the features.
pycityagent/agent.py CHANGED
@@ -9,7 +9,7 @@ from abc import ABC, abstractmethod
9
9
  from copy import deepcopy
10
10
  from datetime import datetime, timezone
11
11
  from enum import Enum
12
- from typing import Any, List, Optional, Type, get_type_hints
12
+ from typing import Any, Optional, Type, get_type_hints
13
13
  from uuid import UUID
14
14
 
15
15
  import fastavro
@@ -49,7 +49,7 @@ class Agent(ABC):
49
49
  """
50
50
  Agent base class
51
51
  """
52
- configurable_fields: List[str] = []
52
+ configurable_fields: list[str] = []
53
53
  default_values: dict[str, Any] = {}
54
54
 
55
55
  def __init__(
@@ -107,7 +107,7 @@ class Agent(ABC):
107
107
  return state
108
108
 
109
109
  @classmethod
110
- def export_class_config(cls) -> Dict[str, Dict]:
110
+ def export_class_config(cls) -> dict[str, Dict]:
111
111
  result = {
112
112
  "agent_name": cls.__name__,
113
113
  "config": {},
@@ -131,7 +131,7 @@ class Agent(ABC):
131
131
  return result
132
132
 
133
133
  @classmethod
134
- def _export_subblocks(cls, block_cls: Type[Block]) -> List[Dict]:
134
+ def _export_subblocks(cls, block_cls: Type[Block]) -> list[Dict]:
135
135
  children = []
136
136
  hints = get_type_hints(block_cls) # 获取类的注解
137
137
  for attr_name, attr_type in hints.items():
@@ -151,7 +151,7 @@ class Agent(ABC):
151
151
  json.dump(config, f, indent=4)
152
152
 
153
153
  @classmethod
154
- def import_block_config(cls, config: Dict[str, List[Dict]]) -> "Agent":
154
+ def import_block_config(cls, config: dict[str, list[Dict]]) -> "Agent":
155
155
  agent = cls(name=config["agent_name"])
156
156
 
157
157
  def build_block(block_data: Dict) -> Block:
@@ -172,7 +172,7 @@ class Agent(ABC):
172
172
  config = json.load(f)
173
173
  return cls.import_block_config(config)
174
174
 
175
- def load_from_config(self, config: Dict[str, List[Dict]]) -> None:
175
+ def load_from_config(self, config: dict[str, list[Dict]]) -> None:
176
176
  """
177
177
  使用配置更新当前Agent实例的Block层次结构。
178
178
  """
@@ -185,7 +185,7 @@ class Agent(ABC):
185
185
  # 递归更新或创建顶层Block
186
186
  for block_data in config.get("blocks", []):
187
187
  block_name = block_data["name"]
188
- existing_block = getattr(self, block_name, None)
188
+ existing_block = getattr(self, block_name, None) # type:ignore
189
189
 
190
190
  if existing_block:
191
191
  # 如果Block已经存在,则递归更新
@@ -1,9 +1,9 @@
1
1
  import asyncio
2
- from collections.abc import Callable
3
2
  import json
4
3
  import logging
5
4
  import time
6
5
  import uuid
6
+ from collections.abc import Callable
7
7
  from datetime import datetime, timezone
8
8
  from pathlib import Path
9
9
  from typing import Any, Optional, Type, Union
@@ -34,7 +34,10 @@ class AgentGroup:
34
34
  self,
35
35
  agent_class: Union[type[Agent], list[type[Agent]]],
36
36
  number_of_agents: Union[int, list[int]],
37
- memory_config_function_group: Union[Callable[[], tuple[dict, dict, dict]], list[Callable[[], tuple[dict, dict, dict]]]],
37
+ memory_config_function_group: Union[
38
+ Callable[[], tuple[dict, dict, dict]],
39
+ list[Callable[[], tuple[dict, dict, dict]]],
40
+ ],
38
41
  config: dict,
39
42
  exp_id: str | UUID,
40
43
  exp_name: str,
@@ -81,14 +84,14 @@ class AgentGroup:
81
84
  # prepare Messager
82
85
  if "mqtt" in config["simulator_request"]:
83
86
  self.messager = Messager.remote(
84
- hostname=config["simulator_request"]["mqtt"]["server"],
87
+ hostname=config["simulator_request"]["mqtt"]["server"], # type:ignore
85
88
  port=config["simulator_request"]["mqtt"]["port"],
86
89
  username=config["simulator_request"]["mqtt"].get("username", None),
87
90
  password=config["simulator_request"]["mqtt"].get("password", None),
88
91
  )
89
92
  else:
90
93
  self.messager = None
91
-
94
+
92
95
  self.message_dispatch_task = None
93
96
  self._pgsql_writer = pgsql_writer
94
97
  self._last_asyncio_pg_task = None # 将SQL写入的IO隐藏到计算任务后
@@ -168,21 +171,21 @@ class AgentGroup:
168
171
  @property
169
172
  def agent_count(self):
170
173
  return self.number_of_agents
171
-
174
+
172
175
  @property
173
176
  def agent_uuids(self):
174
177
  return list(self.id2agent.keys())
175
-
178
+
176
179
  @property
177
180
  def agent_type(self):
178
181
  return self.agent_class
179
-
182
+
180
183
  def get_agent_count(self):
181
184
  return self.agent_count
182
-
185
+
183
186
  def get_agent_uuids(self):
184
187
  return self.agent_uuids
185
-
188
+
186
189
  def get_agent_type(self):
187
190
  return self.agent_type
188
191
 
@@ -190,10 +193,6 @@ class AgentGroup:
190
193
  self.message_dispatch_task.cancel() # type: ignore
191
194
  await asyncio.gather(self.message_dispatch_task, return_exceptions=True) # type: ignore
192
195
 
193
- async def __aexit__(self, exc_type, exc_value, traceback):
194
- self.message_dispatch_task.cancel() # type: ignore
195
- await asyncio.gather(self.message_dispatch_task, return_exceptions=True) # type: ignore
196
-
197
196
  async def init_agents(self):
198
197
  logger.debug(f"-----Initializing Agents in AgentGroup {self._uuid} ...")
199
198
  logger.debug(f"-----Binding Agents to Simulator in AgentGroup {self._uuid} ...")
@@ -201,6 +200,7 @@ class AgentGroup:
201
200
  await agent.bind_to_simulator() # type: ignore
202
201
  self.id2agent = {agent._uuid: agent for agent in self.agents}
203
202
  logger.debug(f"-----Binding Agents to Messager in AgentGroup {self._uuid} ...")
203
+ assert self.messager is not None
204
204
  await self.messager.connect.remote()
205
205
  if await self.messager.is_connected.remote():
206
206
  await self.messager.start_listening.remote()
@@ -293,10 +293,12 @@ class AgentGroup:
293
293
  self.initialized = True
294
294
  logger.debug(f"-----AgentGroup {self._uuid} initialized")
295
295
 
296
- async def filter(self,
297
- types: Optional[list[Type[Agent]]] = None,
298
- keys: Optional[list[str]] = None,
299
- values: Optional[list[Any]] = None) -> list[str]:
296
+ async def filter(
297
+ self,
298
+ types: Optional[list[Type[Agent]]] = None,
299
+ keys: Optional[list[str]] = None,
300
+ values: Optional[list[Any]] = None,
301
+ ) -> list[str]:
300
302
  filtered_uuids = []
301
303
  for agent in self.agents:
302
304
  add = True
@@ -304,6 +306,7 @@ class AgentGroup:
304
306
  if agent.__class__ in types:
305
307
  if keys:
306
308
  for key in keys:
309
+ assert values is not None
307
310
  if not agent.memory.get(key) == values[keys.index(key)]:
308
311
  add = False
309
312
  break
@@ -311,6 +314,7 @@ class AgentGroup:
311
314
  filtered_uuids.append(agent._uuid)
312
315
  elif keys:
313
316
  for key in keys:
317
+ assert values is not None
314
318
  if not agent.memory.get(key) == values[keys.index(key)]:
315
319
  add = False
316
320
  break
@@ -335,6 +339,7 @@ class AgentGroup:
335
339
  async def message_dispatch(self):
336
340
  logger.debug(f"-----Starting message dispatch for group {self._uuid}")
337
341
  while True:
342
+ assert self.messager is not None
338
343
  if not await self.messager.is_connected.remote():
339
344
  logger.warning(
340
345
  "Messager is not connected. Skipping message processing."
@@ -1,10 +1,16 @@
1
- from typing import Any, Optional, Union
1
+ import asyncio
2
+ import time
2
3
  from collections import defaultdict
3
4
  from collections.abc import Callable, Sequence
5
+ from typing import Any, Optional, Union
6
+
4
7
  from mlflow.entities import Metric
5
- import time
6
8
 
7
- from ..environment import LEVEL_ONE_PRE, POI_TYPE_DICT
9
+ from ..agent import Agent
10
+ from ..utils.decorators import lock_decorator
11
+ from ..environment import (LEVEL_ONE_PRE, POI_TYPE_DICT, AoiService,
12
+ PersonService)
13
+ from ..workflow import Block
8
14
 
9
15
 
10
16
  class Tool:
@@ -34,31 +40,23 @@ class Tool:
34
40
  raise NotImplementedError
35
41
 
36
42
  @property
37
- def agent(self):
43
+ def agent(self) -> Agent:
38
44
  instance = self._instance # type:ignore
39
- if not isinstance(instance, self._get_agent_class()):
45
+ if not isinstance(instance, Agent):
40
46
  raise RuntimeError(
41
47
  f"Tool bind to object `{type(instance).__name__}`, not an `Agent` object!"
42
48
  )
43
49
  return instance
44
50
 
45
51
  @property
46
- def block(self):
52
+ def block(self) -> Block:
47
53
  instance = self._instance # type:ignore
48
- if not isinstance(instance, self._get_block_class()):
54
+ if not isinstance(instance, Block):
49
55
  raise RuntimeError(
50
56
  f"Tool bind to object `{type(instance).__name__}`, not an `Block` object!"
51
57
  )
52
58
  return instance
53
59
 
54
- def _get_agent_class(self):
55
- from ..agent import Agent
56
- return Agent
57
-
58
- def _get_block_class(self):
59
- from ..workflow import Block
60
- return Block
61
-
62
60
 
63
61
  class GetMap(Tool):
64
62
  """Retrieve the map from the simulator. Can be bound only to an `Agent` instance."""
@@ -140,7 +138,7 @@ class SencePOI(Tool):
140
138
 
141
139
  class UpdateWithSimulator(Tool):
142
140
  def __init__(self) -> None:
143
- pass
141
+ self._lock = asyncio.Lock()
144
142
 
145
143
  async def _update_motion_with_sim(
146
144
  self,
@@ -164,6 +162,7 @@ class UpdateWithSimulator(Tool):
164
162
  except KeyError as e:
165
163
  continue
166
164
 
165
+ @lock_decorator
167
166
  async def __call__(
168
167
  self,
169
168
  ):
@@ -173,8 +172,9 @@ class UpdateWithSimulator(Tool):
173
172
 
174
173
  class ResetAgentPosition(Tool):
175
174
  def __init__(self) -> None:
176
- pass
175
+ self._lock = asyncio.Lock()
177
176
 
177
+ @lock_decorator
178
178
  async def __call__(
179
179
  self,
180
180
  aoi_id: Optional[int] = None,
@@ -198,7 +198,8 @@ class ExportMlflowMetrics(Tool):
198
198
  self._log_batch_size = log_batch_size
199
199
  # TODO: support other log types
200
200
  self.metric_log_cache: dict[str, list[Metric]] = defaultdict(list)
201
-
201
+ self._lock = asyncio.Lock()
202
+ @lock_decorator
202
203
  async def __call__(
203
204
  self,
204
205
  metric: Union[Sequence[Union[Metric, dict]], Union[Metric, dict]],
@@ -230,7 +231,7 @@ class ExportMlflowMetrics(Tool):
230
231
  _cache = _cache[batch_size:]
231
232
  if clear_cache:
232
233
  await self._clear_cache()
233
-
234
+ @lock_decorator
234
235
  async def _clear_cache(
235
236
  self,
236
237
  ):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pycityagent
3
- Version: 2.0.0a48
3
+ Version: 2.0.0a49
4
4
  Summary: LLM-based city environment agent building library
5
5
  Author-email: Yuwei Yan <pinkgranite86@gmail.com>, Junbo Yan <yanjb20thu@gmali.com>, Jun Zhang <zhangjun990222@gmali.com>
6
6
  License: MIT License
@@ -1,7 +1,7 @@
1
1
  pycityagent/pycityagent-sim,sha256=n96jlVZRINlBec5SPOGAdUmeLWMoEKGgoH29iOVJ0wE,34081890
2
2
  pycityagent/__init__.py,sha256=9sHyzo8monlBPDe7LTlxCIHeNPYj8HJJDCeuJrYJLsQ,750
3
3
  pycityagent/pycityagent-ui,sha256=cHZjqtrQ4Fh4qtRahFNCNbT2DNHLmUexiDAa-72Z3RQ,40333378
4
- pycityagent/agent.py,sha256=PgrtwgcUwTrBtjQPvXxnE2GnYiG2xtG4Ev0oRzd4eec,34017
4
+ pycityagent/agent.py,sha256=iaF83y344V29-jghx5bJD3yY8kMuSzInBPNi7cVxYiA,34026
5
5
  pycityagent/metrics/mlflow_client.py,sha256=g_tHxWkWTDijtbGL74-HmiYzWVKb1y8-w12QrY9jL30,4449
6
6
  pycityagent/metrics/__init__.py,sha256=X08PaBbGVAd7_PRGLREXWxaqm7nS82WBQpD1zvQzcqc,128
7
7
  pycityagent/metrics/utils/const.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -23,7 +23,7 @@ pycityagent/memory/faiss_query.py,sha256=Z0JS4udyPYCIzHMq464QtHscnswu35gh9fQptik
23
23
  pycityagent/memory/state.py,sha256=TYItiyDtehMEQaSBN7PpNrnNxdDM5jGppr9R9Ufv3kA,5134
24
24
  pycityagent/simulation/simulation.py,sha256=7Y1r5DAFaB1vuDd3l_85NWpHQUy2GLkFEb800xsJr0E,25565
25
25
  pycityagent/simulation/__init__.py,sha256=P5czbcg2d8S0nbbnsQXFIhwzO4CennAhZM8OmKvAeYw,194
26
- pycityagent/simulation/agentgroup.py,sha256=MwvsWn3UxoY9qbTSCI0SdG9OnQ22Tk1czIfm-0vRbzI,29343
26
+ pycityagent/simulation/agentgroup.py,sha256=DGN6q9S65K9gSv_ihBeT6iJ__LJhl27yXBFyLEk55t0,29302
27
27
  pycityagent/simulation/storage/pg.py,sha256=5itxKOkNPlOzN7z2_3oKU1ZK0uLTDugfld8ZkRbD69I,8407
28
28
  pycityagent/message/__init__.py,sha256=TCjazxqb5DVwbTu1fF0sNvaH_EPXVuj2XQ0p6W-QCLU,55
29
29
  pycityagent/message/messager.py,sha256=78K31EPKfC5IxbISc-Lc2babC7VOh9Vbe3c0sO-YDLA,3333
@@ -40,7 +40,7 @@ pycityagent/cli/wrapper.py,sha256=2Tb52gOlEVgn11Ekt6ZkRXr_BGzte-EPyBKnR6g6hQ4,11
40
40
  pycityagent/workflow/__init__.py,sha256=QNkUV-9mACMrR8c0cSKna2gC1mMZdxXbxWzjE-Uods0,621
41
41
  pycityagent/workflow/prompt.py,sha256=6jI0Rq54JLv3-IXqZLYug62vse10wTI83xvf4ZX42nk,2929
42
42
  pycityagent/workflow/block.py,sha256=8pK17DGX8MnFJHq5lJ4susdZ-CDAEIjlTV_2mJxhbbw,9600
43
- pycityagent/workflow/tool.py,sha256=jSO8lruDXPLkt4sJJuXvAuaV2XBMXZee_MfQqPo66AQ,8640
43
+ pycityagent/workflow/tool.py,sha256=ChuN5Sm-yltesemewjnTOYaxN6NUjfi2MezVuclf6Tc,8776
44
44
  pycityagent/workflow/trigger.py,sha256=Df-MOBEDWBbM-v0dFLQLXteLsipymT4n8vqexmK2GiQ,5643
45
45
  pycityagent/environment/__init__.py,sha256=awHxlOud-btWbk0FCS4RmGJ13W84oVCkbGfcrhKqihA,240
46
46
  pycityagent/environment/simulator.py,sha256=1OUfODDzM4EN6Lw_Wzq4KeQb-EpcUBioZYc9fxfSPn0,12070
@@ -92,9 +92,9 @@ pycityagent/cityagent/blocks/mobility_block.py,sha256=ZebloDhvZJYbV0YSWhAbnOLToi
92
92
  pycityagent/survey/models.py,sha256=YE50UUt5qJ0O_lIUsSY6XFCGUTkJVNu_L1gAhaCJ2fs,3546
93
93
  pycityagent/survey/__init__.py,sha256=rxwou8U9KeFSP7rMzXtmtp2fVFZxK4Trzi-psx9LPIs,153
94
94
  pycityagent/survey/manager.py,sha256=S5IkwTdelsdtZETChRcfCEczzwSrry_Fly9MY4s3rbk,1681
95
- pycityagent-2.0.0a48.dist-info/RECORD,,
96
- pycityagent-2.0.0a48.dist-info/LICENSE,sha256=n2HPXiupinpyHMnIkbCf3OTYd3KMqbmldu1e7av0CAU,1084
97
- pycityagent-2.0.0a48.dist-info/WHEEL,sha256=76LiH1wuDHqtCdrF20bc1KNGPhF-AWvwbfgCxtm-4DY,109
98
- pycityagent-2.0.0a48.dist-info/entry_points.txt,sha256=BZcne49AAIFv-hawxGnPbblea7X3MtAtoPyDX8L4OC4,132
99
- pycityagent-2.0.0a48.dist-info/top_level.txt,sha256=yOmeu6cSXmiUtScu53a3s0p7BGtLMaV0aff83EHCTic,43
100
- pycityagent-2.0.0a48.dist-info/METADATA,sha256=FtexuISKTOX_w9zQTOv-pXMHQcrkoJWHeNnMgxz37hY,9139
95
+ pycityagent-2.0.0a49.dist-info/RECORD,,
96
+ pycityagent-2.0.0a49.dist-info/LICENSE,sha256=n2HPXiupinpyHMnIkbCf3OTYd3KMqbmldu1e7av0CAU,1084
97
+ pycityagent-2.0.0a49.dist-info/WHEEL,sha256=76LiH1wuDHqtCdrF20bc1KNGPhF-AWvwbfgCxtm-4DY,109
98
+ pycityagent-2.0.0a49.dist-info/entry_points.txt,sha256=BZcne49AAIFv-hawxGnPbblea7X3MtAtoPyDX8L4OC4,132
99
+ pycityagent-2.0.0a49.dist-info/top_level.txt,sha256=yOmeu6cSXmiUtScu53a3s0p7BGtLMaV0aff83EHCTic,43
100
+ pycityagent-2.0.0a49.dist-info/METADATA,sha256=AArJCX11voHGW5AlMrin1qZoj8iVGdOD9XLODRcQwUY,9139