pycityagent 2.0.0a65__cp311-cp311-macosx_11_0_arm64.whl → 2.0.0a67__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.
- pycityagent/agent/agent.py +157 -57
- pycityagent/agent/agent_base.py +316 -43
- pycityagent/cityagent/bankagent.py +49 -9
- pycityagent/cityagent/blocks/__init__.py +1 -2
- pycityagent/cityagent/blocks/cognition_block.py +54 -31
- pycityagent/cityagent/blocks/dispatcher.py +22 -17
- pycityagent/cityagent/blocks/economy_block.py +46 -32
- pycityagent/cityagent/blocks/mobility_block.py +209 -105
- pycityagent/cityagent/blocks/needs_block.py +101 -54
- pycityagent/cityagent/blocks/other_block.py +42 -33
- pycityagent/cityagent/blocks/plan_block.py +59 -42
- pycityagent/cityagent/blocks/social_block.py +167 -126
- pycityagent/cityagent/blocks/utils.py +13 -6
- pycityagent/cityagent/firmagent.py +17 -35
- pycityagent/cityagent/governmentagent.py +3 -3
- pycityagent/cityagent/initial.py +79 -49
- pycityagent/cityagent/memory_config.py +123 -94
- pycityagent/cityagent/message_intercept.py +0 -4
- pycityagent/cityagent/metrics.py +41 -0
- pycityagent/cityagent/nbsagent.py +24 -36
- pycityagent/cityagent/societyagent.py +9 -4
- pycityagent/cli/wrapper.py +2 -2
- pycityagent/economy/econ_client.py +407 -81
- pycityagent/environment/__init__.py +0 -3
- pycityagent/environment/sim/__init__.py +0 -3
- pycityagent/environment/sim/aoi_service.py +2 -2
- pycityagent/environment/sim/client.py +3 -31
- pycityagent/environment/sim/clock_service.py +2 -2
- pycityagent/environment/sim/lane_service.py +8 -8
- pycityagent/environment/sim/light_service.py +8 -8
- pycityagent/environment/sim/pause_service.py +9 -10
- pycityagent/environment/sim/person_service.py +20 -20
- pycityagent/environment/sim/road_service.py +2 -2
- pycityagent/environment/sim/sim_env.py +21 -5
- pycityagent/environment/sim/social_service.py +4 -4
- pycityagent/environment/simulator.py +249 -27
- pycityagent/environment/utils/__init__.py +2 -2
- pycityagent/environment/utils/geojson.py +2 -2
- pycityagent/environment/utils/grpc.py +4 -4
- pycityagent/environment/utils/map_utils.py +2 -2
- pycityagent/llm/embeddings.py +147 -28
- pycityagent/llm/llm.py +178 -111
- pycityagent/llm/llmconfig.py +5 -0
- pycityagent/llm/utils.py +4 -0
- pycityagent/memory/__init__.py +0 -4
- pycityagent/memory/const.py +2 -2
- pycityagent/memory/faiss_query.py +140 -61
- pycityagent/memory/memory.py +394 -91
- pycityagent/memory/memory_base.py +140 -34
- pycityagent/memory/profile.py +13 -13
- pycityagent/memory/self_define.py +13 -13
- pycityagent/memory/state.py +14 -14
- pycityagent/message/message_interceptor.py +253 -3
- pycityagent/message/messager.py +133 -6
- pycityagent/metrics/mlflow_client.py +47 -4
- pycityagent/pycityagent-sim +0 -0
- pycityagent/pycityagent-ui +0 -0
- pycityagent/simulation/__init__.py +3 -2
- pycityagent/simulation/agentgroup.py +150 -54
- pycityagent/simulation/simulation.py +276 -66
- pycityagent/survey/manager.py +45 -3
- pycityagent/survey/models.py +42 -2
- pycityagent/tools/__init__.py +1 -2
- pycityagent/tools/tool.py +93 -69
- pycityagent/utils/avro_schema.py +2 -2
- pycityagent/utils/parsers/code_block_parser.py +1 -1
- pycityagent/utils/parsers/json_parser.py +2 -2
- pycityagent/utils/parsers/parser_base.py +2 -2
- pycityagent/workflow/block.py +64 -13
- pycityagent/workflow/prompt.py +31 -23
- pycityagent/workflow/trigger.py +91 -24
- {pycityagent-2.0.0a65.dist-info → pycityagent-2.0.0a67.dist-info}/METADATA +2 -2
- pycityagent-2.0.0a67.dist-info/RECORD +97 -0
- pycityagent/environment/interact/__init__.py +0 -0
- pycityagent/environment/interact/interact.py +0 -198
- pycityagent/environment/message/__init__.py +0 -0
- pycityagent/environment/sence/__init__.py +0 -0
- pycityagent/environment/sence/static.py +0 -416
- pycityagent/environment/sidecar/__init__.py +0 -8
- pycityagent/environment/sidecar/sidecarv2.py +0 -109
- pycityagent/environment/sim/economy_services.py +0 -192
- pycityagent/metrics/utils/const.py +0 -0
- pycityagent-2.0.0a65.dist-info/RECORD +0 -105
- {pycityagent-2.0.0a65.dist-info → pycityagent-2.0.0a67.dist-info}/LICENSE +0 -0
- {pycityagent-2.0.0a65.dist-info → pycityagent-2.0.0a67.dist-info}/WHEEL +0 -0
- {pycityagent-2.0.0a65.dist-info → pycityagent-2.0.0a67.dist-info}/entry_points.txt +0 -0
- {pycityagent-2.0.0a65.dist-info → pycityagent-2.0.0a67.dist-info}/top_level.txt +0 -0
@@ -15,6 +15,8 @@ from mlflow.entities import (Dataset, DatasetInput, Document, Experiment,
|
|
15
15
|
|
16
16
|
from ..utils.decorators import lock_decorator
|
17
17
|
|
18
|
+
__all__ = ["init_mlflow_connection","MlflowClient",]
|
19
|
+
|
18
20
|
logger = logging.getLogger("mlflow")
|
19
21
|
|
20
22
|
|
@@ -26,7 +28,20 @@ def init_mlflow_connection(
|
|
26
28
|
experiment_description: Optional[str] = None,
|
27
29
|
experiment_tags: Optional[dict[str, Any]] = None,
|
28
30
|
) -> tuple[str, tuple[str, mlflow.MlflowClient, Run, str]]:
|
29
|
-
|
31
|
+
"""
|
32
|
+
Initialize an MLflow connection with a new or existing experiment and run.
|
33
|
+
|
34
|
+
- **Args**:
|
35
|
+
config (dict): Configuration dictionary containing MLflow credentials and URI.
|
36
|
+
experiment_uuid (str): A unique identifier for the experiment.
|
37
|
+
mlflow_run_name (str, optional): Name of the MLflow run. Defaults to a generated name.
|
38
|
+
experiment_name (str, optional): Name of the experiment. Defaults to a generated name.
|
39
|
+
experiment_description (str, optional): Description for the experiment. Defaults to None.
|
40
|
+
experiment_tags (dict, optional): Tags to associate with the experiment. Defaults to None.
|
41
|
+
|
42
|
+
- **Returns**:
|
43
|
+
tuple: A tuple containing the run_id and another tuple with the MLflow URI, client, run object, and run UUID.
|
44
|
+
"""
|
30
45
|
os.environ["MLFLOW_TRACKING_USERNAME"] = config.get("username", None)
|
31
46
|
os.environ["MLFLOW_TRACKING_PASSWORD"] = config.get("password", None)
|
32
47
|
|
@@ -70,9 +85,7 @@ def init_mlflow_connection(
|
|
70
85
|
|
71
86
|
|
72
87
|
class MlflowClient:
|
73
|
-
"""
|
74
|
-
- Mlflow client
|
75
|
-
"""
|
88
|
+
"""A wrapper around MLflow's MlflowClient for managing experiments and runs."""
|
76
89
|
|
77
90
|
def __init__(
|
78
91
|
self,
|
@@ -84,6 +97,18 @@ class MlflowClient:
|
|
84
97
|
experiment_tags: Optional[dict[str, Any]] = None,
|
85
98
|
run_id: Optional[str] = None,
|
86
99
|
) -> None:
|
100
|
+
"""
|
101
|
+
Initialize the MlflowClient.
|
102
|
+
|
103
|
+
- **Args**:
|
104
|
+
config (dict): Configuration dictionary containing MLflow credentials and URI.
|
105
|
+
experiment_uuid (str): A unique identifier for the experiment.
|
106
|
+
mlflow_run_name (str, optional): Name of the MLflow run. Defaults to a generated name.
|
107
|
+
experiment_name (str, optional): Name of the experiment. Defaults to a generated name.
|
108
|
+
experiment_description (str, optional): Description for the experiment. Defaults to None.
|
109
|
+
experiment_tags (dict, optional): Tags to associate with the experiment. Defaults to None.
|
110
|
+
run_id (str, optional): Existing MLflow run ID to attach to. Defaults to None.
|
111
|
+
"""
|
87
112
|
if run_id is None:
|
88
113
|
self._run_id, (
|
89
114
|
self._mlflow_uri,
|
@@ -112,12 +137,14 @@ class MlflowClient:
|
|
112
137
|
def client(
|
113
138
|
self,
|
114
139
|
) -> mlflow.MlflowClient:
|
140
|
+
"""Return the underlying MLflow client."""
|
115
141
|
return self._client
|
116
142
|
|
117
143
|
@property
|
118
144
|
def run_id(
|
119
145
|
self,
|
120
146
|
) -> str:
|
147
|
+
"""Return the current run ID."""
|
121
148
|
assert self._run_id is not None
|
122
149
|
return self._run_id
|
123
150
|
|
@@ -128,6 +155,11 @@ class MlflowClient:
|
|
128
155
|
params: Sequence[Param] = (),
|
129
156
|
tags: Sequence[RunTag] = (),
|
130
157
|
):
|
158
|
+
"""
|
159
|
+
Log a batch of metrics, parameters, and tags to the MLflow run.
|
160
|
+
|
161
|
+
This method is thread-safe due to the `@lock_decorator`.
|
162
|
+
"""
|
131
163
|
self.client.log_batch(
|
132
164
|
run_id=self.run_id, metrics=metrics, params=params, tags=tags
|
133
165
|
)
|
@@ -140,6 +172,17 @@ class MlflowClient:
|
|
140
172
|
step: Optional[int] = None,
|
141
173
|
timestamp: Optional[int] = None,
|
142
174
|
):
|
175
|
+
"""
|
176
|
+
Log a single metric to the MLflow run.
|
177
|
+
|
178
|
+
This method is thread-safe due to the `@lock_decorator`.
|
179
|
+
|
180
|
+
- **Args**:
|
181
|
+
key (str): The name of the metric.
|
182
|
+
value (float): The value of the metric.
|
183
|
+
step (int, optional): The step at which the metric was recorded. Defaults to None.
|
184
|
+
timestamp (int, optional): The timestamp when the metric was recorded. Defaults to None.
|
185
|
+
"""
|
143
186
|
if timestamp is not None:
|
144
187
|
timestamp = int(timestamp)
|
145
188
|
self.client.log_metric(
|
pycityagent/pycityagent-sim
CHANGED
Binary file
|
pycityagent/pycityagent-ui
CHANGED
Binary file
|
@@ -26,6 +26,7 @@ from ..utils import (DIALOG_SCHEMA, INSTITUTION_STATUS_SCHEMA, PROFILE_SCHEMA,
|
|
26
26
|
STATUS_SCHEMA, SURVEY_SCHEMA)
|
27
27
|
|
28
28
|
logger = logging.getLogger("pycityagent")
|
29
|
+
__all__ = ["AgentGroup"]
|
29
30
|
|
30
31
|
|
31
32
|
@ray.remote
|
@@ -37,7 +38,7 @@ class AgentGroup:
|
|
37
38
|
memory_config_function_group: dict[type[Agent], Callable],
|
38
39
|
config: dict,
|
39
40
|
exp_name: str,
|
40
|
-
exp_id: str
|
41
|
+
exp_id: Union[str, UUID],
|
41
42
|
enable_avro: bool,
|
42
43
|
avro_path: Path,
|
43
44
|
enable_pgsql: bool,
|
@@ -49,6 +50,33 @@ class AgentGroup:
|
|
49
50
|
agent_config_file: Optional[dict[type[Agent], str]] = None,
|
50
51
|
environment: Optional[dict[str, str]] = None,
|
51
52
|
):
|
53
|
+
"""
|
54
|
+
Represents a group of agents that can be deployed in a Ray distributed environment.
|
55
|
+
|
56
|
+
- **Description**:
|
57
|
+
- Manages the creation and initialization of multiple agents, each potentially of different types,
|
58
|
+
with associated memory configurations, and connects them to various services such as MLflow, MQTT messager,
|
59
|
+
PostgreSQL writer, message interceptor, and LLM client. It also sets up an economy client and simulator for
|
60
|
+
agent interaction within a simulated environment.
|
61
|
+
|
62
|
+
- **Args**:
|
63
|
+
- `agent_class` (Union[Type[Agent], List[Type[Agent]]]): A single or list of agent classes to instantiate.
|
64
|
+
- `number_of_agents` (Union[int, List[int]]): Number of instances to create for each agent class.
|
65
|
+
- `memory_config_function_group` (Dict[Type[Agent], Callable]): Functions to configure memory for each agent type.
|
66
|
+
- `config` (dict): Configuration settings for the agent group.
|
67
|
+
- `exp_name` (str): Name of the experiment.
|
68
|
+
- `exp_id` (str | UUID): Identifier for the experiment.
|
69
|
+
- `enable_avro` (bool): Flag to enable AVRO file support.
|
70
|
+
- `avro_path` (Path): Path where AVRO files will be stored.
|
71
|
+
- `enable_pgsql` (bool): Flag to enable PostgreSQL support.
|
72
|
+
- `pgsql_writer` (ray.ObjectRef): Reference to a PostgreSQL writer object.
|
73
|
+
- `message_interceptor` (ray.ObjectRef): Reference to a message interceptor object.
|
74
|
+
- `mlflow_run_id` (str): Run identifier for MLflow tracking.
|
75
|
+
- `embedding_model` (Embeddings): Model used for generating embeddings.
|
76
|
+
- `logging_level` (int): Logging level for the agent group.
|
77
|
+
- `agent_config_file` (Optional[Dict[Type[Agent], str]], optional): File paths for loading agent configurations. Defaults to None.
|
78
|
+
- `environment` (Optional[Dict[str, str]], optional): Environment variables for the simulator. Defaults to None.
|
79
|
+
"""
|
52
80
|
logger.setLevel(logging_level)
|
53
81
|
self._uuid = str(uuid.uuid4())
|
54
82
|
if not isinstance(agent_class, list):
|
@@ -112,12 +140,13 @@ class AgentGroup:
|
|
112
140
|
llmConfig = LLMConfig(config["llm_request"])
|
113
141
|
logger.info(f"-----Creating LLM client in AgentGroup {self._uuid} ...")
|
114
142
|
self.llm = LLM(llmConfig)
|
143
|
+
self.llm.set_semaphore(200)
|
115
144
|
|
116
145
|
# prepare Simulator
|
117
146
|
logger.info(f"-----Creating Simulator in AgentGroup {self._uuid} ...")
|
118
147
|
self.simulator = Simulator(config["simulator_request"])
|
119
148
|
self.projector = pyproj.Proj(self.simulator.map.header["projection"])
|
120
|
-
self.simulator.set_environment(environment)
|
149
|
+
self.simulator.set_environment(environment) # type:ignore
|
121
150
|
# prepare Economy client
|
122
151
|
logger.info(f"-----Creating Economy client in AgentGroup {self._uuid} ...")
|
123
152
|
self.economy_client = EconomyClient(
|
@@ -135,7 +164,9 @@ class AgentGroup:
|
|
135
164
|
agent_class_i = agent_class[i]
|
136
165
|
number_of_agents_i = number_of_agents[i]
|
137
166
|
for j in range(number_of_agents_i):
|
138
|
-
memory_config_function_group_i = memory_config_function_group[
|
167
|
+
memory_config_function_group_i = memory_config_function_group[
|
168
|
+
agent_class_i
|
169
|
+
]
|
139
170
|
extra_attributes, profile, base = memory_config_function_group_i()
|
140
171
|
memory = Memory(config=extra_attributes, profile=profile, base=base)
|
141
172
|
agent = agent_class_i(
|
@@ -154,7 +185,10 @@ class AgentGroup:
|
|
154
185
|
agent.set_avro_file(self.avro_file) # type: ignore
|
155
186
|
if self.enable_pgsql:
|
156
187
|
agent.set_pgsql_writer(self._pgsql_writer)
|
157
|
-
if
|
188
|
+
if (
|
189
|
+
self.agent_config_file is not None
|
190
|
+
and self.agent_config_file[agent_class_i]
|
191
|
+
):
|
158
192
|
agent.load_from_file(self.agent_config_file[agent_class_i])
|
159
193
|
if self._message_interceptor is not None:
|
160
194
|
agent.set_message_interceptor(self._message_interceptor)
|
@@ -172,6 +206,12 @@ class AgentGroup:
|
|
172
206
|
@property
|
173
207
|
def agent_type(self):
|
174
208
|
return self.agent_class
|
209
|
+
|
210
|
+
async def get_economy_ids(self):
|
211
|
+
return await self.economy_client.get_ids()
|
212
|
+
|
213
|
+
async def set_economy_ids(self, agent_ids: set[int], org_ids: set[int]):
|
214
|
+
await self.economy_client.set_ids(agent_ids, org_ids)
|
175
215
|
|
176
216
|
def get_agent_count(self):
|
177
217
|
return self.agent_count
|
@@ -186,7 +226,7 @@ class AgentGroup:
|
|
186
226
|
self.message_dispatch_task.cancel() # type: ignore
|
187
227
|
await asyncio.gather(self.message_dispatch_task, return_exceptions=True) # type: ignore
|
188
228
|
|
189
|
-
async def
|
229
|
+
async def insert_agent(self):
|
190
230
|
bind_tasks = []
|
191
231
|
for agent in self.agents:
|
192
232
|
bind_tasks.append(agent.bind_to_simulator()) # type: ignore
|
@@ -200,7 +240,7 @@ class AgentGroup:
|
|
200
240
|
if day == 0:
|
201
241
|
break
|
202
242
|
await asyncio.sleep(1)
|
203
|
-
await self.
|
243
|
+
await self.insert_agent()
|
204
244
|
self.id2agent = {agent._uuid: agent for agent in self.agents}
|
205
245
|
logger.debug(f"-----Binding Agents to Messager in AgentGroup {self._uuid} ...")
|
206
246
|
assert self.messager is not None
|
@@ -314,6 +354,17 @@ class AgentGroup:
|
|
314
354
|
keys: Optional[list[str]] = None,
|
315
355
|
values: Optional[list[Any]] = None,
|
316
356
|
) -> list[str]:
|
357
|
+
"""
|
358
|
+
Filters agents based on type and/or key-value pairs in their status.
|
359
|
+
|
360
|
+
- **Args**:
|
361
|
+
- `types` (Optional[List[Type[Agent]]]): A list of agent types to filter by.
|
362
|
+
- `keys` (Optional[List[str]]): A list of keys to check in the agent's status.
|
363
|
+
- `values` (Optional[List[Any]]): The corresponding values for each key in the `keys` list.
|
364
|
+
|
365
|
+
- **Returns**:
|
366
|
+
- `List[str]`: A list of UUIDs for agents that match the filter criteria.
|
367
|
+
"""
|
317
368
|
filtered_uuids = []
|
318
369
|
for agent in self.agents:
|
319
370
|
add = True
|
@@ -340,6 +391,16 @@ class AgentGroup:
|
|
340
391
|
async def gather(
|
341
392
|
self, content: str, target_agent_uuids: Optional[list[str]] = None
|
342
393
|
):
|
394
|
+
"""
|
395
|
+
Gathers specific content from all or targeted agents within the group.
|
396
|
+
|
397
|
+
- **Args**:
|
398
|
+
- `content` (str): The key of the status content to gather from the agents.
|
399
|
+
- `target_agent_uuids` (Optional[List[str]]): A list of agent UUIDs to target. If None, targets all agents.
|
400
|
+
|
401
|
+
- **Returns**:
|
402
|
+
- `Dict[str, Any]`: A dictionary mapping agent UUIDs to the gathered content.
|
403
|
+
"""
|
343
404
|
logger.debug(f"-----Gathering {content} from all agents in group {self._uuid}")
|
344
405
|
results = {}
|
345
406
|
if target_agent_uuids is None:
|
@@ -350,6 +411,14 @@ class AgentGroup:
|
|
350
411
|
return results
|
351
412
|
|
352
413
|
async def update(self, target_agent_uuid: str, target_key: str, content: Any):
|
414
|
+
"""
|
415
|
+
Updates a specific key in the status of a targeted agent.
|
416
|
+
|
417
|
+
- **Args**:
|
418
|
+
- `target_agent_uuid` (str): The UUID of the agent to update.
|
419
|
+
- `target_key` (str): The key in the agent's status to update.
|
420
|
+
- `content` (Any): The new value for the specified key.
|
421
|
+
"""
|
353
422
|
logger.debug(
|
354
423
|
f"-----Updating {target_key} for agent {target_agent_uuid} in group {self._uuid}"
|
355
424
|
)
|
@@ -357,9 +426,25 @@ class AgentGroup:
|
|
357
426
|
await agent.status.update(target_key, content)
|
358
427
|
|
359
428
|
async def update_environment(self, key: str, value: str):
|
429
|
+
"""
|
430
|
+
Updates the environment with a given key-value pair.
|
431
|
+
|
432
|
+
- **Args**:
|
433
|
+
- `key` (str): The key to update in the environment.
|
434
|
+
- `value` (str): The value to set for the specified key.
|
435
|
+
"""
|
360
436
|
self.simulator.update_environment(key, value)
|
361
437
|
|
362
438
|
async def message_dispatch(self):
|
439
|
+
"""
|
440
|
+
Dispatches messages received via MQTT to the appropriate agents.
|
441
|
+
|
442
|
+
- **Description**:
|
443
|
+
- Continuously listens for incoming MQTT messages and dispatches them to the relevant agents based on the topic.
|
444
|
+
- Messages are expected to have a topic formatted as "exps/{exp_id}/agents/{agent_uuid}/{topic_type}".
|
445
|
+
- The payload is decoded from bytes to string and then parsed as JSON.
|
446
|
+
- Depending on the `topic_type`, different handler methods on the agent are called to process the message.
|
447
|
+
"""
|
363
448
|
logger.debug(f"-----Starting message dispatch for group {self._uuid}")
|
364
449
|
while True:
|
365
450
|
assert self.messager is not None
|
@@ -402,6 +487,13 @@ class AgentGroup:
|
|
402
487
|
async def save_status(
|
403
488
|
self, simulator_day: Optional[int] = None, simulator_t: Optional[int] = None
|
404
489
|
):
|
490
|
+
"""
|
491
|
+
Saves the current status of the agents at a given point in the simulation.
|
492
|
+
|
493
|
+
- **Args**:
|
494
|
+
- `simulator_day` (Optional[int]): The day number in the simulation time.
|
495
|
+
- `simulator_t` (Optional[int]): The tick or time unit in the simulation day.
|
496
|
+
"""
|
405
497
|
_statuses_time_list: list[tuple[dict, datetime]] = []
|
406
498
|
if self.enable_avro:
|
407
499
|
logger.debug(f"-----Saving status for group {self._uuid} with Avro")
|
@@ -603,54 +695,18 @@ class AgentGroup:
|
|
603
695
|
lng, lat = self.projector(x, y, inverse=True)
|
604
696
|
# ATTENTION: no valid position for an institution
|
605
697
|
parent_id = -1
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
try:
|
619
|
-
wages = await agent.status.get("wages")
|
620
|
-
except:
|
621
|
-
wages = []
|
622
|
-
try:
|
623
|
-
prices = await agent.status.get("prices")
|
624
|
-
except:
|
625
|
-
prices = []
|
626
|
-
try:
|
627
|
-
inventory = await agent.status.get("inventory")
|
628
|
-
except:
|
629
|
-
inventory = 0
|
630
|
-
try:
|
631
|
-
price = await agent.status.get("price")
|
632
|
-
except:
|
633
|
-
price = 0.0
|
634
|
-
try:
|
635
|
-
interest_rate = await agent.status.get("interest_rate")
|
636
|
-
except:
|
637
|
-
interest_rate = 0.0
|
638
|
-
try:
|
639
|
-
bracket_cutoffs = await agent.status.get("bracket_cutoffs")
|
640
|
-
except:
|
641
|
-
bracket_cutoffs = []
|
642
|
-
try:
|
643
|
-
bracket_rates = await agent.status.get("bracket_rates")
|
644
|
-
except:
|
645
|
-
bracket_rates = []
|
646
|
-
try:
|
647
|
-
employees = await agent.status.get("employees")
|
648
|
-
except:
|
649
|
-
employees = []
|
650
|
-
try:
|
651
|
-
friend_ids = await agent.status.get("friends")
|
652
|
-
except:
|
653
|
-
friend_ids = []
|
698
|
+
nominal_gdp = await agent.status.get("nominal_gdp", [])
|
699
|
+
real_gdp = await agent.status.get("real_gdp", [])
|
700
|
+
unemployment = await agent.status.get("unemployment", [])
|
701
|
+
wages = await agent.status.get("wages", [])
|
702
|
+
prices = await agent.status.get("prices", [])
|
703
|
+
inventory = await agent.status.get("inventory", 0)
|
704
|
+
price = await agent.status.get("price", 0.0)
|
705
|
+
interest_rate = await agent.status.get("interest_rate", 0.0)
|
706
|
+
bracket_cutoffs = await agent.status.get("bracket_cutoffs", [])
|
707
|
+
bracket_rates = await agent.status.get("bracket_rates", [])
|
708
|
+
employees = await agent.status.get("employees", [])
|
709
|
+
friend_ids = await agent.status.get("friends", [])
|
654
710
|
_status_dict = {
|
655
711
|
"id": agent._uuid,
|
656
712
|
"day": _day,
|
@@ -705,10 +761,40 @@ class AgentGroup:
|
|
705
761
|
)
|
706
762
|
)
|
707
763
|
|
764
|
+
def get_llm_consumption(self):
|
765
|
+
"""
|
766
|
+
Retrieves the consumption statistics from the LLM client.
|
767
|
+
|
768
|
+
- **Returns**:
|
769
|
+
- The consumption data provided by the LLM client.
|
770
|
+
"""
|
771
|
+
return self.llm.get_consumption()
|
772
|
+
|
708
773
|
async def step(self):
|
774
|
+
"""
|
775
|
+
Executes a single simulation step by running all agents concurrently.
|
776
|
+
|
777
|
+
- **Description**:
|
778
|
+
- This method initiates the `run` coroutine for each agent in parallel using asyncio.gather.
|
779
|
+
- Any exceptions raised during the execution are caught, logged, and re-raised as a RuntimeError.
|
780
|
+
|
781
|
+
- **Raises**:
|
782
|
+
- `RuntimeError`: If an exception occurs during the execution of any agent's `run` method.
|
783
|
+
"""
|
709
784
|
try:
|
710
785
|
tasks = [agent.run() for agent in self.agents]
|
711
786
|
await asyncio.gather(*tasks)
|
787
|
+
simulator_log = self.simulator.get_log_list() + self.economy_client.get_log_list()
|
788
|
+
group_logs = {
|
789
|
+
"llm_log": self.llm.get_log_list(),
|
790
|
+
"mqtt_log": ray.get(self.messager.get_log_list.remote()),
|
791
|
+
"simulator_log": simulator_log
|
792
|
+
}
|
793
|
+
self.llm.clear_log_list()
|
794
|
+
self.messager.clear_log_list.remote()
|
795
|
+
self.simulator.clear_log_list()
|
796
|
+
self.economy_client.clear_log_list()
|
797
|
+
return group_logs
|
712
798
|
except Exception as e:
|
713
799
|
import traceback
|
714
800
|
|
@@ -716,6 +802,16 @@ class AgentGroup:
|
|
716
802
|
raise RuntimeError(str(e)) from e
|
717
803
|
|
718
804
|
async def save(self, day: int, t: int):
|
805
|
+
"""
|
806
|
+
Saves the current status of the agents at a given point in the simulation.
|
807
|
+
|
808
|
+
- **Args**:
|
809
|
+
- `day` (int): The day number in the simulation time.
|
810
|
+
- `t` (int): The tick or time unit within the simulation day.
|
811
|
+
|
812
|
+
- **Raises**:
|
813
|
+
- `RuntimeError`: If an exception occurs while saving the status.
|
814
|
+
"""
|
719
815
|
try:
|
720
816
|
await self.save_status(day, t)
|
721
817
|
except Exception as e:
|