pycityagent 2.0.0a1__py3-none-any.whl → 2.0.0a3__py3-none-any.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.
@@ -1,10 +1,38 @@
1
1
  import asyncio
2
- from typing import Any, Callable, Dict, List, Optional, Union
2
+ from typing import Any, Callable, Dict, List, Optional, Union, Type
3
3
  import socket
4
4
  from ..memory import Memory
5
+ from ..environment import Simulator
6
+
7
+ KEY_TRIGGER_COMPONENTS = [Memory, Simulator]
5
8
 
6
9
  class EventTrigger:
7
10
  """Base class for event triggers that wait for specific conditions to be met."""
11
+ # 定义该trigger需要的组件类型
12
+ required_components: List[Type] = []
13
+
14
+ def __init__(self, block=None):
15
+ self.block = block
16
+ if block is not None:
17
+ self.initialize()
18
+
19
+ def initialize(self) -> None:
20
+ """Initialize the trigger with necessary dependencies."""
21
+ if not self.block:
22
+ raise RuntimeError("Block not set for trigger")
23
+
24
+ # 检查所需组件是否都存在
25
+ missing_components = []
26
+ for component_type in self.required_components:
27
+ component_name = component_type.__name__.lower()
28
+ if not hasattr(self.block, component_name):
29
+ missing_components.append(component_type.__name__)
30
+
31
+ if missing_components:
32
+ raise RuntimeError(
33
+ f"Block is missing required components for {self.__class__.__name__}: "
34
+ f"{', '.join(missing_components)}"
35
+ )
8
36
 
9
37
  async def wait_for_trigger(self) -> None:
10
38
  """Wait for the event trigger to be activated.
@@ -16,51 +44,107 @@ class EventTrigger:
16
44
 
17
45
  class MemoryChangeTrigger(EventTrigger):
18
46
  """Event trigger that activates when a specific key in memory changes."""
47
+ required_components = [Memory]
19
48
 
20
- def __init__(self, memory: Memory, key: str) -> None:
49
+ def __init__(self, key: str) -> None:
21
50
  """Initialize the memory change trigger.
22
51
 
23
52
  Args:
24
- memory (Memory): The memory object to watch.
25
53
  key (str): The key in memory to monitor for changes.
26
54
  """
27
- self.memory = memory
28
55
  self.key = key
29
56
  self.trigger_event = asyncio.Event()
30
- asyncio.create_task(self.memory.add_watcher(key, self.trigger_event.set))
57
+ self._initialized = False
58
+ super().__init__()
59
+
60
+ def initialize(self) -> None:
61
+ """Initialize the trigger with memory from block."""
62
+ super().initialize() # 首先检查必需组件
63
+ self.memory = self.block.memory
64
+ asyncio.create_task(self.memory.add_watcher(self.key, self.trigger_event.set))
65
+ self._initialized = True
31
66
 
32
67
  async def wait_for_trigger(self) -> None:
33
68
  """Wait for the memory change trigger to be activated."""
69
+ if not self._initialized:
70
+ raise RuntimeError("Trigger not properly initialized")
34
71
  await self.trigger_event.wait()
35
72
  self.trigger_event.clear()
36
73
 
37
- class PortMessageTrigger(EventTrigger):
38
- """Event trigger that activates upon receiving a message on a specified UDP port."""
74
+
75
+ class TimeTrigger(EventTrigger):
76
+ """Event trigger that activates periodically based on time intervals."""
77
+ required_components = [Simulator]
39
78
 
40
- def __init__(self, port: int) -> None:
41
- """Initialize the port message trigger.
79
+ def __init__(self,
80
+ days: Optional[int] = None,
81
+ hours: Optional[int] = None,
82
+ minutes: Optional[int] = None) -> None:
83
+ """Initialize the time trigger with interval settings.
42
84
 
43
85
  Args:
44
- port (int): The UDP port to listen for incoming messages.
86
+ days (Optional[int]): Execute every N days
87
+ hours (Optional[int]): Execute every N hours
88
+ minutes (Optional[int]): Execute every N minutes
89
+
90
+ Raises:
91
+ ValueError: If all interval parameters are None or negative
45
92
  """
46
- self.port = port
93
+ if all(param is None for param in (days, hours, minutes)):
94
+ raise ValueError("At least one time interval must be specified")
95
+
96
+ # 验证参数有效性
97
+ for param_name, param_value in [('days', days), ('hours', hours), ('minutes', minutes)]:
98
+ if param_value is not None and param_value < 0:
99
+ raise ValueError(f"{param_name} cannot be negative")
100
+
101
+ # 将所有时间间隔转换为秒
102
+ self.interval = 0
103
+ if days is not None:
104
+ self.interval += days * 24 * 60 * 60
105
+ if hours is not None:
106
+ self.interval += hours * 60 * 60
107
+ if minutes is not None:
108
+ self.interval += minutes * 60
109
+
47
110
  self.trigger_event = asyncio.Event()
48
- self.message: Optional[str] = None
49
- asyncio.create_task(self._listen_on_port())
111
+ self._initialized = False
112
+ self._monitoring_task = None
113
+ self._last_trigger_time = None
114
+ super().__init__()
50
115
 
51
- async def _listen_on_port(self) -> None:
52
- """Listen for incoming UDP messages on the specified port.
116
+ def initialize(self) -> None:
117
+ """Initialize the trigger with necessary dependencies."""
118
+ super().initialize() # 首先检查必需组件
119
+ self.memory = self.block.memory
120
+ self.simulator = self.block.simulator
121
+ # 启动时间监控任务
122
+ self._monitoring_task = asyncio.create_task(self._monitor_time())
123
+ self._initialized = True
53
124
 
54
- Activates the trigger event when a message is received.
55
- """
56
- with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
57
- s.bind(("", self.port))
58
- while True:
59
- data, _ = s.recvfrom(1024)
60
- self.message = data.decode()
61
- self.trigger_event.set()
125
+ async def _monitor_time(self):
126
+ """持续监控时间并在达到间隔时触发事件"""
127
+ # 第一次调用时直接触发
128
+ self.trigger_event.set()
129
+
130
+ while True:
131
+ try:
132
+ current_time = await self.simulator.GetTime()
133
+
134
+ # 如果是第一次或者已经过了指定的时间间隔
135
+ if (self._last_trigger_time is None or
136
+ current_time - self._last_trigger_time >= self.interval):
137
+ self._last_trigger_time = current_time
138
+ self.trigger_event.set()
139
+
140
+ await asyncio.sleep(5) # 避免过于频繁的检查
141
+ except Exception as e:
142
+ print(f"Error in time monitoring: {e}")
143
+ await asyncio.sleep(10) # 发生错误时等待较长时间
62
144
 
63
145
  async def wait_for_trigger(self) -> None:
64
- """Wait for the port message trigger to be activated."""
146
+ """Wait for the time trigger to be activated."""
147
+ if not self._initialized:
148
+ raise RuntimeError("Trigger not properly initialized")
65
149
  await self.trigger_event.wait()
66
150
  self.trigger_event.clear()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pycityagent
3
- Version: 2.0.0a1
3
+ Version: 2.0.0a3
4
4
  Summary: LLM-based城市环境agent构建库
5
5
  License: MIT
6
6
  Author: Yuwei Yan
@@ -1,5 +1,5 @@
1
1
  pycityagent/__init__.py,sha256=n56bWkAUEcvjDsb7LcJpaGjlrriSKPnR0yBhwRfEYBA,212
2
- pycityagent/agent.py,sha256=hfJbvZ5kxJJ3AAWjGdEzy52Rid3T5fVq8Qm0djnfxUY,6005
2
+ pycityagent/agent.py,sha256=QzVBgTdlwZEY0pQQB9nTruWiIc3t8mZxLzv5cId1IbY,5951
3
3
  pycityagent/config.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
4
  pycityagent/economy/__init__.py,sha256=aonY4WHnx-6EGJ4WKrx4S-2jAkYNLtqUA04jp6q8B7w,75
5
5
  pycityagent/economy/econ_client.py,sha256=qQb_kZneEXGBRaS_y5Jdoi95I8GyjKEsDSC4s6V6R7w,10829
@@ -11,7 +11,7 @@ pycityagent/environment/sence/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5N
11
11
  pycityagent/environment/sence/static.py,sha256=fdBjHKacNiDCKhvQkc9WgEYYSO0peMC5lb8CcXl9iNc,29101
12
12
  pycityagent/environment/sidecar/__init__.py,sha256=RFbOf40aYBP4WwRpFkua5tlRE_OtMcMNyp1Lew_aaAU,235
13
13
  pycityagent/environment/sidecar/sidecarv2.py,sha256=beKlYZgt38EQbV1x6NWQo7xVXyB-5QHfbwJexyXu7Tg,3252
14
- pycityagent/environment/sim/__init__.py,sha256=tr0lFAUsbyfAN5W5GehTlJHTSDGLeseUqVJgZfWn6PY,668
14
+ pycityagent/environment/sim/__init__.py,sha256=JVG6sSD2Hbohl1TtKjuQi7_M7tKMrFh9vl3QV3VA5O0,724
15
15
  pycityagent/environment/sim/aoi_service.py,sha256=pYSsqdGBpfQvp0-umNJir_7Yph75OJqhLjFQ2QWhSP8,1211
16
16
  pycityagent/environment/sim/client.py,sha256=MHR7Hhu-Cr7B61d3K_QDpSJh4HrUU9JQf6Cu7_8pdsE,3493
17
17
  pycityagent/environment/sim/clock_service.py,sha256=YG_A_IA7iJp9rOQE3bCPgppzuzzUwWMCzlxSUdOy088,1326
@@ -20,12 +20,16 @@ pycityagent/environment/sim/lane_service.py,sha256=6ljWiX_GbZd-a-fEcktDZncxBkraL
20
20
  pycityagent/environment/sim/light_service.py,sha256=ezYGcV_PkZ6I-yv48LNEjsytwwwQx-1Qp2QCWXWIhdQ,4215
21
21
  pycityagent/environment/sim/person_service.py,sha256=nIvOsoBoqOTDYtsiThg07-4ZBgkTUDEbb3dHyOjzyb8,10652
22
22
  pycityagent/environment/sim/road_service.py,sha256=Pab182YRcrjLw3UcfoD1Hdd6O8XEdi6Q2hJKzFcpSWE,1272
23
+ pycityagent/environment/sim/sim_env.py,sha256=HI1LcS_FotDKQ6vBnx0e49prXSABOfA20aU9KM-ZkCY,4625
23
24
  pycityagent/environment/sim/social_service.py,sha256=a9mGZm95EFUIKQJUwQi9f8anmtf2SK4XqGfE2W9IXSQ,2001
24
- pycityagent/environment/simulator.py,sha256=zF6jBJLYtv-xqmFPKfrO_Z2u3FHDjRZ6segZhJbe7M8,13289
25
- pycityagent/environment/utils/__init__.py,sha256=sYbR0Przx6eekKXoTDDNB6u-cOaKfqsF0NYypppHuK8,116
25
+ pycityagent/environment/simulator.py,sha256=lw6-T6HFeE6lOtbTQdKZLre2cX7PZkXftRt7wC4mE-8,11858
26
+ pycityagent/environment/utils/__init__.py,sha256=PUx8etr2p_AA7F50ZR7g27odkgv-nOqFZa61ER8-DLg,221
27
+ pycityagent/environment/utils/base64.py,sha256=hoREzQo3FXMN79pqQLO2jgsDEvudciomyKii7MWljAM,374
28
+ pycityagent/environment/utils/const.py,sha256=3RMNy7_bE7-23K90j9DFW_tWEzu8s7hSTgKbV-3BFl4,5327
26
29
  pycityagent/environment/utils/geojson.py,sha256=Ieg8Bzw63kKhJlhDIOVDoh-wQO4Sbtoe47FtIOy5wWg,686
27
30
  pycityagent/environment/utils/grpc.py,sha256=6EJwKXXktIWb1NcUiJzIRmfrY0S03QAXXGcCDHqAT00,1998
28
31
  pycityagent/environment/utils/map_utils.py,sha256=oqrRgQICC3SYw6gwjjPe_MAif7_t6dlrQpY8E32Fexs,5777
32
+ pycityagent/environment/utils/port.py,sha256=3OM6kSUt3PxvDUOlgyiendBtETaWU8Mzk_8H0TzTmYg,295
29
33
  pycityagent/environment/utils/protobuf.py,sha256=0jBvK_s96y_n7tuMbG22TOtQmg71SGV4ONDy2IGsU9o,1148
30
34
  pycityagent/llm/__init__.py,sha256=0-_q-StY0g4p9mdUNve_kqzHNXwVxedNsvxGXSQYq6o,144
31
35
  pycityagent/llm/embedding.py,sha256=vtjMUuInrtn0WRPXp3cmYEhwHXJ0q6zszdXsjTsgNeQ,4499
@@ -43,7 +47,7 @@ pycityagent/memory/utils.py,sha256=97lkenn-36wgt7uWb3Z39BXdJ5zlEQTQnQBFpoND1gg,8
43
47
  pycityagent/message/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
44
48
  pycityagent/simulation/__init__.py,sha256=SZQzjcGR-zkTDrE81bQuEdKn7yjk4BcZ9m7o1wTc7EE,111
45
49
  pycityagent/simulation/interview.py,sha256=mY4Vpz0vgJo4rrMy3TZnwwM-iVDL6J0LgjOxbEuV27E,1173
46
- pycityagent/simulation/simulation.py,sha256=RXB0esX_0kS_gB8_zaVjPVQRHJYZ6iSYH44d_Uksf2s,10016
50
+ pycityagent/simulation/simulation.py,sha256=-vm0Yhl_k4_CbGYScg-V4dD2KEyLiarN27u0ccaX8ao,12680
47
51
  pycityagent/simulation/survey/__init__.py,sha256=hFJ0Q1yo4jwKAIXP17sznBSWwm2Lyh3F3W3Lly40wr8,172
48
52
  pycityagent/simulation/survey/manager.py,sha256=DkNrb12Ay7TiGURoyJTFFeUdV1zh6TgRpTmpZOblADw,2158
49
53
  pycityagent/simulation/survey/models.py,sha256=-3EKe-qvkUJ2TH24ow0A_Lc4teGet7pueN2T5mOR_Qc,1308
@@ -55,11 +59,11 @@ pycityagent/utils/parsers/__init__.py,sha256=p5RZ4azJIpMgmKIU2evIp2moNzFabIR9X1L
55
59
  pycityagent/utils/parsers/code_block_parser.py,sha256=Cs2Z_hm9VfNCpPPll1TwteaJF-HAQPs-3RApsOekFm4,1173
56
60
  pycityagent/utils/parsers/json_parser.py,sha256=FZ3XN1g8z4Dr2TFraUOoah1oQcze4fPd2m01hHoX0Mo,2917
57
61
  pycityagent/utils/parsers/parser_base.py,sha256=k6DVqwAMK3jJdOP4IeLE-aFPm3V2F-St5qRBuRdx4aU,1742
58
- pycityagent/workflow/__init__.py,sha256=dQCK7diOAQAn8Fo73rb6cnw-7u2NC55JWLW02bLdHLU,495
59
- pycityagent/workflow/block.py,sha256=rRL4ajiRZq3el4W0n6U4Ytb4WlN_4tH9OvVgFEuh73c,5093
62
+ pycityagent/workflow/__init__.py,sha256=EyCcjB6LyBim-5iAOPe4m2qfvghEPqu1ZdGfy4KPeZ8,551
63
+ pycityagent/workflow/block.py,sha256=IXfarqIax6yVP_DniU6ZsPTT8QA4aIDnvZbwP_MtRaw,6054
60
64
  pycityagent/workflow/prompt.py,sha256=cmzKEmlzjdwg50uwfnTnN_6xNJA8OVjo5fdmcsaTbdU,2886
61
65
  pycityagent/workflow/tool.py,sha256=4sYbH-OVNffXbK3m58f8ap6WrS_uMzhK1c_Rl2er1B0,8981
62
- pycityagent/workflow/trigger.py,sha256=vweibjzGFex8IyRH7BbU-yarXcIgo6lt9v0UN3e7l5w,2352
63
- pycityagent-2.0.0a1.dist-info/METADATA,sha256=84-4cu5JguETBEEV63jJgKr_0XtYx78zS0ZDqpE79FE,7537
64
- pycityagent-2.0.0a1.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
65
- pycityagent-2.0.0a1.dist-info/RECORD,,
66
+ pycityagent/workflow/trigger.py,sha256=u2aPBOzTWvdYKb45nUsQfA_uRunsmbLzB7ztSU2mlrQ,5736
67
+ pycityagent-2.0.0a3.dist-info/METADATA,sha256=C5Mcssb-bkqMJEBYu3MsqGTqfjgH__gFo_3w9wItFAA,7537
68
+ pycityagent-2.0.0a3.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
69
+ pycityagent-2.0.0a3.dist-info/RECORD,,