pycityagent 2.0.0a14__tar.gz → 2.0.0a15__tar.gz
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-2.0.0a14 → pycityagent-2.0.0a15}/PKG-INFO +1 -1
- pycityagent-2.0.0a15/pycityagent/__init__.py +22 -0
- {pycityagent-2.0.0a14 → pycityagent-2.0.0a15}/pycityagent/agent.py +44 -31
- {pycityagent-2.0.0a14 → pycityagent-2.0.0a15}/pycityagent/environment/simulator.py +5 -4
- {pycityagent-2.0.0a14 → pycityagent-2.0.0a15}/pycityagent/memory/memory.py +8 -7
- {pycityagent-2.0.0a14 → pycityagent-2.0.0a15}/pycityagent/memory/memory_base.py +6 -4
- {pycityagent-2.0.0a14 → pycityagent-2.0.0a15}/pycityagent/message/messager.py +8 -7
- pycityagent-2.0.0a15/pycityagent/simulation/agentgroup.py +273 -0
- {pycityagent-2.0.0a14 → pycityagent-2.0.0a15}/pycityagent/simulation/simulation.py +157 -78
- {pycityagent-2.0.0a14 → pycityagent-2.0.0a15}/pycityagent/utils/__init__.py +2 -2
- {pycityagent-2.0.0a14 → pycityagent-2.0.0a15}/pycityagent/utils/avro_schema.py +26 -1
- {pycityagent-2.0.0a14 → pycityagent-2.0.0a15}/pycityagent/workflow/tool.py +0 -3
- {pycityagent-2.0.0a14 → pycityagent-2.0.0a15}/pyproject.toml +1 -1
- pycityagent-2.0.0a14/pycityagent/__init__.py +0 -8
- pycityagent-2.0.0a14/pycityagent/simulation/agentgroup.py +0 -189
- {pycityagent-2.0.0a14 → pycityagent-2.0.0a15}/README.md +0 -0
- {pycityagent-2.0.0a14 → pycityagent-2.0.0a15}/pycityagent/economy/__init__.py +0 -0
- {pycityagent-2.0.0a14 → pycityagent-2.0.0a15}/pycityagent/economy/econ_client.py +0 -0
- {pycityagent-2.0.0a14 → pycityagent-2.0.0a15}/pycityagent/environment/__init__.py +0 -0
- {pycityagent-2.0.0a14 → pycityagent-2.0.0a15}/pycityagent/environment/interact/__init__.py +0 -0
- {pycityagent-2.0.0a14 → pycityagent-2.0.0a15}/pycityagent/environment/interact/interact.py +0 -0
- {pycityagent-2.0.0a14 → pycityagent-2.0.0a15}/pycityagent/environment/message/__init__.py +0 -0
- {pycityagent-2.0.0a14 → pycityagent-2.0.0a15}/pycityagent/environment/sence/__init__.py +0 -0
- {pycityagent-2.0.0a14 → pycityagent-2.0.0a15}/pycityagent/environment/sence/static.py +0 -0
- {pycityagent-2.0.0a14 → pycityagent-2.0.0a15}/pycityagent/environment/sidecar/__init__.py +0 -0
- {pycityagent-2.0.0a14 → pycityagent-2.0.0a15}/pycityagent/environment/sidecar/sidecarv2.py +0 -0
- {pycityagent-2.0.0a14 → pycityagent-2.0.0a15}/pycityagent/environment/sim/__init__.py +0 -0
- {pycityagent-2.0.0a14 → pycityagent-2.0.0a15}/pycityagent/environment/sim/aoi_service.py +0 -0
- {pycityagent-2.0.0a14 → pycityagent-2.0.0a15}/pycityagent/environment/sim/client.py +0 -0
- {pycityagent-2.0.0a14 → pycityagent-2.0.0a15}/pycityagent/environment/sim/clock_service.py +0 -0
- {pycityagent-2.0.0a14 → pycityagent-2.0.0a15}/pycityagent/environment/sim/economy_services.py +0 -0
- {pycityagent-2.0.0a14 → pycityagent-2.0.0a15}/pycityagent/environment/sim/lane_service.py +0 -0
- {pycityagent-2.0.0a14 → pycityagent-2.0.0a15}/pycityagent/environment/sim/light_service.py +0 -0
- {pycityagent-2.0.0a14 → pycityagent-2.0.0a15}/pycityagent/environment/sim/person_service.py +0 -0
- {pycityagent-2.0.0a14 → pycityagent-2.0.0a15}/pycityagent/environment/sim/road_service.py +0 -0
- {pycityagent-2.0.0a14 → pycityagent-2.0.0a15}/pycityagent/environment/sim/sim_env.py +0 -0
- {pycityagent-2.0.0a14 → pycityagent-2.0.0a15}/pycityagent/environment/sim/social_service.py +0 -0
- {pycityagent-2.0.0a14 → pycityagent-2.0.0a15}/pycityagent/environment/utils/__init__.py +0 -0
- {pycityagent-2.0.0a14 → pycityagent-2.0.0a15}/pycityagent/environment/utils/base64.py +0 -0
- {pycityagent-2.0.0a14 → pycityagent-2.0.0a15}/pycityagent/environment/utils/const.py +0 -0
- {pycityagent-2.0.0a14 → pycityagent-2.0.0a15}/pycityagent/environment/utils/geojson.py +0 -0
- {pycityagent-2.0.0a14 → pycityagent-2.0.0a15}/pycityagent/environment/utils/grpc.py +0 -0
- {pycityagent-2.0.0a14 → pycityagent-2.0.0a15}/pycityagent/environment/utils/map_utils.py +0 -0
- {pycityagent-2.0.0a14 → pycityagent-2.0.0a15}/pycityagent/environment/utils/port.py +0 -0
- {pycityagent-2.0.0a14 → pycityagent-2.0.0a15}/pycityagent/environment/utils/protobuf.py +0 -0
- {pycityagent-2.0.0a14 → pycityagent-2.0.0a15}/pycityagent/llm/__init__.py +0 -0
- {pycityagent-2.0.0a14 → pycityagent-2.0.0a15}/pycityagent/llm/embedding.py +0 -0
- {pycityagent-2.0.0a14 → pycityagent-2.0.0a15}/pycityagent/llm/llm.py +0 -0
- {pycityagent-2.0.0a14 → pycityagent-2.0.0a15}/pycityagent/llm/llmconfig.py +0 -0
- {pycityagent-2.0.0a14 → pycityagent-2.0.0a15}/pycityagent/llm/utils.py +0 -0
- {pycityagent-2.0.0a14 → pycityagent-2.0.0a15}/pycityagent/memory/__init__.py +0 -0
- {pycityagent-2.0.0a14 → pycityagent-2.0.0a15}/pycityagent/memory/const.py +0 -0
- {pycityagent-2.0.0a14 → pycityagent-2.0.0a15}/pycityagent/memory/profile.py +0 -0
- {pycityagent-2.0.0a14 → pycityagent-2.0.0a15}/pycityagent/memory/self_define.py +0 -0
- {pycityagent-2.0.0a14 → pycityagent-2.0.0a15}/pycityagent/memory/state.py +0 -0
- {pycityagent-2.0.0a14 → pycityagent-2.0.0a15}/pycityagent/memory/utils.py +0 -0
- {pycityagent-2.0.0a14 → pycityagent-2.0.0a15}/pycityagent/message/__init__.py +0 -0
- {pycityagent-2.0.0a14 → pycityagent-2.0.0a15}/pycityagent/simulation/__init__.py +0 -0
- {pycityagent-2.0.0a14 → pycityagent-2.0.0a15}/pycityagent/survey/__init__.py +0 -0
- {pycityagent-2.0.0a14 → pycityagent-2.0.0a15}/pycityagent/survey/manager.py +0 -0
- {pycityagent-2.0.0a14 → pycityagent-2.0.0a15}/pycityagent/survey/models.py +0 -0
- {pycityagent-2.0.0a14 → pycityagent-2.0.0a15}/pycityagent/utils/decorators.py +0 -0
- {pycityagent-2.0.0a14 → pycityagent-2.0.0a15}/pycityagent/utils/parsers/__init__.py +0 -0
- {pycityagent-2.0.0a14 → pycityagent-2.0.0a15}/pycityagent/utils/parsers/code_block_parser.py +0 -0
- {pycityagent-2.0.0a14 → pycityagent-2.0.0a15}/pycityagent/utils/parsers/json_parser.py +0 -0
- {pycityagent-2.0.0a14 → pycityagent-2.0.0a15}/pycityagent/utils/parsers/parser_base.py +0 -0
- {pycityagent-2.0.0a14 → pycityagent-2.0.0a15}/pycityagent/utils/survey_util.py +0 -0
- {pycityagent-2.0.0a14 → pycityagent-2.0.0a15}/pycityagent/workflow/__init__.py +0 -0
- {pycityagent-2.0.0a14 → pycityagent-2.0.0a15}/pycityagent/workflow/block.py +0 -0
- {pycityagent-2.0.0a14 → pycityagent-2.0.0a15}/pycityagent/workflow/prompt.py +0 -0
- {pycityagent-2.0.0a14 → pycityagent-2.0.0a15}/pycityagent/workflow/trigger.py +0 -0
@@ -0,0 +1,22 @@
|
|
1
|
+
"""
|
2
|
+
Pycityagent: 城市智能体构建框架
|
3
|
+
"""
|
4
|
+
|
5
|
+
from .agent import Agent, CitizenAgent, InstitutionAgent
|
6
|
+
from .environment import Simulator
|
7
|
+
import logging
|
8
|
+
|
9
|
+
# 创建一个 pycityagent 记录器
|
10
|
+
logger = logging.getLogger("pycityagent")
|
11
|
+
logger.setLevel(logging.WARNING) # 默认级别
|
12
|
+
|
13
|
+
# 如果没有处理器,则添加一个
|
14
|
+
if not logger.hasHandlers():
|
15
|
+
handler = logging.StreamHandler()
|
16
|
+
formatter = logging.Formatter(
|
17
|
+
"%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
18
|
+
)
|
19
|
+
handler.setFormatter(formatter)
|
20
|
+
logger.addHandler(handler)
|
21
|
+
|
22
|
+
__all__ = ["Agent", "Simulator", "CitizenAgent", "InstitutionAgent"]
|
@@ -2,11 +2,9 @@
|
|
2
2
|
|
3
3
|
from abc import ABC, abstractmethod
|
4
4
|
import asyncio
|
5
|
-
import json
|
6
5
|
from uuid import UUID
|
7
6
|
from copy import deepcopy
|
8
7
|
from datetime import datetime
|
9
|
-
import time
|
10
8
|
from enum import Enum
|
11
9
|
import logging
|
12
10
|
import random
|
@@ -28,6 +26,8 @@ from .environment import Simulator
|
|
28
26
|
from .llm import LLM
|
29
27
|
from .memory import Memory
|
30
28
|
|
29
|
+
logger = logging.getLogger("pycityagent")
|
30
|
+
|
31
31
|
|
32
32
|
class AgentType(Enum):
|
33
33
|
"""
|
@@ -73,7 +73,7 @@ class Agent(ABC):
|
|
73
73
|
"""
|
74
74
|
self._name = name
|
75
75
|
self._type = type
|
76
|
-
self._uuid = uuid.uuid4()
|
76
|
+
self._uuid = str(uuid.uuid4())
|
77
77
|
self._llm_client = llm_client
|
78
78
|
self._economy_client = economy_client
|
79
79
|
self._messager = messager
|
@@ -123,12 +123,18 @@ class Agent(ABC):
|
|
123
123
|
"""
|
124
124
|
self._memory = memory
|
125
125
|
|
126
|
-
def set_exp_id(self, exp_id: str
|
126
|
+
def set_exp_id(self, exp_id: str):
|
127
127
|
"""
|
128
128
|
Set the exp_id of the agent.
|
129
129
|
"""
|
130
130
|
self._exp_id = exp_id
|
131
131
|
|
132
|
+
def set_avro_file(self, avro_file: Dict[str, str]):
|
133
|
+
"""
|
134
|
+
Set the avro file of the agent.
|
135
|
+
"""
|
136
|
+
self._avro_file = avro_file
|
137
|
+
|
132
138
|
@property
|
133
139
|
def uuid(self):
|
134
140
|
"""The Agent's UUID"""
|
@@ -214,8 +220,10 @@ class Agent(ABC):
|
|
214
220
|
|
215
221
|
async def _process_survey(self, survey: dict):
|
216
222
|
survey_response = await self.generate_user_survey_response(survey)
|
223
|
+
if self._avro_file is None:
|
224
|
+
return
|
217
225
|
response_to_avro = [{
|
218
|
-
"id":
|
226
|
+
"id": self._uuid,
|
219
227
|
"day": await self._simulator.get_simulator_day(),
|
220
228
|
"t": await self._simulator.get_simulator_second_from_start_of_day(),
|
221
229
|
"survey_id": survey["id"],
|
@@ -264,7 +272,7 @@ class Agent(ABC):
|
|
264
272
|
|
265
273
|
async def _process_interview(self, payload: dict):
|
266
274
|
auros = [{
|
267
|
-
"id":
|
275
|
+
"id": self._uuid,
|
268
276
|
"day": await self._simulator.get_simulator_day(),
|
269
277
|
"t": await self._simulator.get_simulator_second_from_start_of_day(),
|
270
278
|
"type": 2,
|
@@ -275,7 +283,7 @@ class Agent(ABC):
|
|
275
283
|
question = payload["content"]
|
276
284
|
response = await self.generate_user_chat_response(question)
|
277
285
|
auros.append({
|
278
|
-
"id":
|
286
|
+
"id": self._uuid,
|
279
287
|
"day": await self._simulator.get_simulator_day(),
|
280
288
|
"t": await self._simulator.get_simulator_second_from_start_of_day(),
|
281
289
|
"type": 2,
|
@@ -283,15 +291,17 @@ class Agent(ABC):
|
|
283
291
|
"content": response,
|
284
292
|
"created_at": int(datetime.now().timestamp() * 1000),
|
285
293
|
})
|
294
|
+
if self._avro_file is None:
|
295
|
+
return
|
286
296
|
with open(self._avro_file["dialog"], "a+b") as f:
|
287
297
|
fastavro.writer(f, DIALOG_SCHEMA, auros, codec="snappy")
|
288
298
|
|
289
299
|
async def process_agent_chat_response(self, payload: dict) -> str:
|
290
|
-
|
300
|
+
logger.info(f"Agent {self._uuid} received agent chat response: {payload}")
|
291
301
|
|
292
302
|
async def _process_agent_chat(self, payload: dict):
|
293
303
|
auros = [{
|
294
|
-
"id":
|
304
|
+
"id": self._uuid,
|
295
305
|
"day": payload["day"],
|
296
306
|
"t": payload["t"],
|
297
307
|
"type": 1,
|
@@ -300,6 +310,8 @@ class Agent(ABC):
|
|
300
310
|
"created_at": int(datetime.now().timestamp() * 1000),
|
301
311
|
}]
|
302
312
|
asyncio.create_task(self.process_agent_chat_response(payload))
|
313
|
+
if self._avro_file is None:
|
314
|
+
return
|
303
315
|
with open(self._avro_file["dialog"], "a+b") as f:
|
304
316
|
fastavro.writer(f, DIALOG_SCHEMA, auros, codec="snappy")
|
305
317
|
|
@@ -307,19 +319,19 @@ class Agent(ABC):
|
|
307
319
|
async def handle_agent_chat_message(self, payload: dict):
|
308
320
|
"""处理收到的消息,识别发送者"""
|
309
321
|
# 从消息中解析发送者 ID 和消息内容
|
310
|
-
|
322
|
+
logger.info(f"Agent {self._uuid} received agent chat message: {payload}")
|
311
323
|
asyncio.create_task(self._process_agent_chat(payload))
|
312
324
|
|
313
325
|
async def handle_user_chat_message(self, payload: dict):
|
314
326
|
"""处理收到的消息,识别发送者"""
|
315
327
|
# 从消息中解析发送者 ID 和消息内容
|
316
|
-
|
328
|
+
logger.info(f"Agent {self._uuid} received user chat message: {payload}")
|
317
329
|
asyncio.create_task(self._process_interview(payload))
|
318
330
|
|
319
331
|
async def handle_user_survey_message(self, payload: dict):
|
320
332
|
"""处理收到的消息,识别发送者"""
|
321
333
|
# 从消息中解析发送者 ID 和消息内容
|
322
|
-
|
334
|
+
logger.info(f"Agent {self._uuid} received user survey message: {payload}")
|
323
335
|
asyncio.create_task(self._process_survey(payload["data"]))
|
324
336
|
|
325
337
|
async def handle_gather_message(self, payload: str):
|
@@ -327,7 +339,7 @@ class Agent(ABC):
|
|
327
339
|
|
328
340
|
# MQTT send message
|
329
341
|
async def _send_message(
|
330
|
-
self, to_agent_uuid:
|
342
|
+
self, to_agent_uuid: str, payload: dict, sub_topic: str
|
331
343
|
):
|
332
344
|
"""通过 Messager 发送消息"""
|
333
345
|
if self._messager is None:
|
@@ -336,7 +348,7 @@ class Agent(ABC):
|
|
336
348
|
await self._messager.send_message(topic, payload)
|
337
349
|
|
338
350
|
async def send_message_to_agent(
|
339
|
-
self, to_agent_uuid:
|
351
|
+
self, to_agent_uuid: str, content: str
|
340
352
|
):
|
341
353
|
"""通过 Messager 发送消息"""
|
342
354
|
if self._messager is None:
|
@@ -350,14 +362,16 @@ class Agent(ABC):
|
|
350
362
|
}
|
351
363
|
await self._send_message(to_agent_uuid, payload, "agent-chat")
|
352
364
|
auros = [{
|
353
|
-
"id":
|
365
|
+
"id": self._uuid,
|
354
366
|
"day": await self._simulator.get_simulator_day(),
|
355
367
|
"t": await self._simulator.get_simulator_second_from_start_of_day(),
|
356
368
|
"type": 1,
|
357
|
-
"speaker":
|
369
|
+
"speaker": self._uuid,
|
358
370
|
"content": content,
|
359
371
|
"created_at": int(datetime.now().timestamp() * 1000),
|
360
372
|
}]
|
373
|
+
if self._avro_file is None:
|
374
|
+
return
|
361
375
|
with open(self._avro_file["dialog"], "a+b") as f:
|
362
376
|
fastavro.writer(f, DIALOG_SCHEMA, auros, codec="snappy")
|
363
377
|
|
@@ -414,7 +428,7 @@ class CitizenAgent(Agent):
|
|
414
428
|
person_template (dict, optional): The person template in dict format. Defaults to PersonService.default_dict_person().
|
415
429
|
"""
|
416
430
|
if self._simulator is None:
|
417
|
-
|
431
|
+
logger.warning("Simulator is not set")
|
418
432
|
return
|
419
433
|
if not self._has_bound_to_simulator:
|
420
434
|
FROM_MEMORY_KEYS = {
|
@@ -432,7 +446,7 @@ class CitizenAgent(Agent):
|
|
432
446
|
# ATTENTION:模拟器分配的id从0开始
|
433
447
|
if person_id >= 0:
|
434
448
|
await simulator.get_person(person_id)
|
435
|
-
|
449
|
+
logger.debug(f"Binding to Person `{person_id}` already in Simulator")
|
436
450
|
else:
|
437
451
|
dict_person = deepcopy(self._person_template)
|
438
452
|
for _key in FROM_MEMORY_KEYS:
|
@@ -447,7 +461,7 @@ class CitizenAgent(Agent):
|
|
447
461
|
)
|
448
462
|
person_id = resp["person_id"]
|
449
463
|
await memory.update("id", person_id, protect_llm_read_only_fields=False)
|
450
|
-
|
464
|
+
logger.debug(
|
451
465
|
f"Binding to Person `{person_id}` just added to Simulator"
|
452
466
|
)
|
453
467
|
# 防止模拟器还没有到prepare阶段导致get_person出错
|
@@ -456,7 +470,7 @@ class CitizenAgent(Agent):
|
|
456
470
|
|
457
471
|
async def _bind_to_economy(self):
|
458
472
|
if self._economy_client is None:
|
459
|
-
|
473
|
+
logger.warning("Economy client is not set")
|
460
474
|
return
|
461
475
|
if not self._has_bound_to_economy:
|
462
476
|
if self._has_bound_to_simulator:
|
@@ -473,7 +487,7 @@ class CitizenAgent(Agent):
|
|
473
487
|
)
|
474
488
|
self._has_bound_to_economy = True
|
475
489
|
else:
|
476
|
-
|
490
|
+
logger.debug(
|
477
491
|
f"Binding to Economy before binding to Simulator, skip binding to Economy Simulator"
|
478
492
|
)
|
479
493
|
|
@@ -523,7 +537,7 @@ class InstitutionAgent(Agent):
|
|
523
537
|
|
524
538
|
async def _bind_to_economy(self):
|
525
539
|
if self._economy_client is None:
|
526
|
-
|
540
|
+
logger.debug("Economy client is not set")
|
527
541
|
return
|
528
542
|
if not self._has_bound_to_economy:
|
529
543
|
# TODO: More general id generation
|
@@ -599,7 +613,7 @@ class InstitutionAgent(Agent):
|
|
599
613
|
}
|
600
614
|
)
|
601
615
|
except Exception as e:
|
602
|
-
|
616
|
+
logger.error(f"Failed to bind to Economy: {e}")
|
603
617
|
self._has_bound_to_economy = True
|
604
618
|
|
605
619
|
async def handle_gather_message(self, payload: dict):
|
@@ -615,11 +629,11 @@ class InstitutionAgent(Agent):
|
|
615
629
|
"content": content,
|
616
630
|
})
|
617
631
|
|
618
|
-
async def gather_messages(self,
|
632
|
+
async def gather_messages(self, agent_uuids: list[str], target: str) -> List[dict]:
|
619
633
|
"""从多个智能体收集消息
|
620
634
|
|
621
635
|
Args:
|
622
|
-
|
636
|
+
agent_uuids: 目标智能体UUID列表
|
623
637
|
target: 要收集的信息类型
|
624
638
|
|
625
639
|
Returns:
|
@@ -627,18 +641,17 @@ class InstitutionAgent(Agent):
|
|
627
641
|
"""
|
628
642
|
# 为每个agent创建Future
|
629
643
|
futures = {}
|
630
|
-
for
|
631
|
-
|
632
|
-
|
633
|
-
self._gather_responses[response_key] = futures[response_key]
|
644
|
+
for agent_uuid in agent_uuids:
|
645
|
+
futures[agent_uuid] = asyncio.Future()
|
646
|
+
self._gather_responses[agent_uuid] = futures[agent_uuid]
|
634
647
|
|
635
648
|
# 发送gather请求
|
636
649
|
payload = {
|
637
650
|
"from": self._uuid,
|
638
651
|
"target": target,
|
639
652
|
}
|
640
|
-
for
|
641
|
-
await self._send_message(
|
653
|
+
for agent_uuid in agent_uuids:
|
654
|
+
await self._send_message(agent_uuid, payload, "gather")
|
642
655
|
|
643
656
|
try:
|
644
657
|
# 等待所有响应
|
@@ -20,6 +20,7 @@ from shapely.strtree import STRtree
|
|
20
20
|
from .sim import CityClient, ControlSimEnv
|
21
21
|
from .utils.const import *
|
22
22
|
|
23
|
+
logger = logging.getLogger("pycityagent")
|
23
24
|
|
24
25
|
class Simulator:
|
25
26
|
"""
|
@@ -72,7 +73,7 @@ class Simulator:
|
|
72
73
|
else:
|
73
74
|
self._client = CityClient(config["simulator"]["server"], secure=False)
|
74
75
|
else:
|
75
|
-
|
76
|
+
logger.warning(
|
76
77
|
"No simulator config found, no simulator client will be used"
|
77
78
|
)
|
78
79
|
self.map = SimMap(
|
@@ -285,7 +286,7 @@ class Simulator:
|
|
285
286
|
reset_position["aoi_position"] = {"aoi_id": aoi_id}
|
286
287
|
if poi_id is not None:
|
287
288
|
reset_position["aoi_position"]["poi_id"] = poi_id
|
288
|
-
|
289
|
+
logger.debug(
|
289
290
|
f"Setting person {person_id} pos to AoiPosition {reset_position}"
|
290
291
|
)
|
291
292
|
await self._client.person_service.ResetPersonPosition(
|
@@ -298,14 +299,14 @@ class Simulator:
|
|
298
299
|
}
|
299
300
|
if s is not None:
|
300
301
|
reset_position["lane_position"]["s"] = s
|
301
|
-
|
302
|
+
logger.debug(
|
302
303
|
f"Setting person {person_id} pos to LanePosition {reset_position}"
|
303
304
|
)
|
304
305
|
await self._client.person_service.ResetPersonPosition(
|
305
306
|
{"person_id": person_id, "position": reset_position}
|
306
307
|
)
|
307
308
|
else:
|
308
|
-
|
309
|
+
logger.debug(
|
309
310
|
f"Neither aoi or lane pos provided for person {person_id} position reset!!"
|
310
311
|
)
|
311
312
|
|
@@ -13,6 +13,7 @@ from .profile import ProfileMemory
|
|
13
13
|
from .self_define import DynamicMemory
|
14
14
|
from .state import StateMemory
|
15
15
|
|
16
|
+
logger = logging.getLogger("pycityagent")
|
16
17
|
|
17
18
|
class Memory:
|
18
19
|
"""
|
@@ -83,7 +84,7 @@ class Memory:
|
|
83
84
|
_type.extend(_value)
|
84
85
|
_value = deepcopy(_type)
|
85
86
|
else:
|
86
|
-
|
87
|
+
logger.warning(f"type `{_type}` is not supported!")
|
87
88
|
pass
|
88
89
|
except TypeError as e:
|
89
90
|
pass
|
@@ -99,7 +100,7 @@ class Memory:
|
|
99
100
|
or k in STATE_ATTRIBUTES
|
100
101
|
or k == TIME_STAMP_KEY
|
101
102
|
):
|
102
|
-
|
103
|
+
logger.warning(f"key `{k}` already declared in memory!")
|
103
104
|
continue
|
104
105
|
|
105
106
|
_dynamic_config[k] = deepcopy(_value)
|
@@ -112,19 +113,19 @@ class Memory:
|
|
112
113
|
if profile is not None:
|
113
114
|
for k, v in profile.items():
|
114
115
|
if k not in PROFILE_ATTRIBUTES:
|
115
|
-
|
116
|
+
logger.warning(f"key `{k}` is not a correct `profile` field!")
|
116
117
|
continue
|
117
118
|
_profile_config[k] = v
|
118
119
|
if motion is not None:
|
119
120
|
for k, v in motion.items():
|
120
121
|
if k not in STATE_ATTRIBUTES:
|
121
|
-
|
122
|
+
logger.warning(f"key `{k}` is not a correct `motion` field!")
|
122
123
|
continue
|
123
124
|
_state_config[k] = v
|
124
125
|
if base is not None:
|
125
126
|
for k, v in base.items():
|
126
127
|
if k not in STATE_ATTRIBUTES:
|
127
|
-
|
128
|
+
logger.warning(f"key `{k}` is not a correct `base` field!")
|
128
129
|
continue
|
129
130
|
_state_config[k] = v
|
130
131
|
self._state = StateMemory(
|
@@ -182,7 +183,7 @@ class Memory:
|
|
182
183
|
"""更新记忆值并在必要时更新embedding"""
|
183
184
|
if protect_llm_read_only_fields:
|
184
185
|
if any(key in _attrs for _attrs in [STATE_ATTRIBUTES]):
|
185
|
-
|
186
|
+
logger.warning(f"Trying to write protected key `{key}`!")
|
186
187
|
return
|
187
188
|
for _mem in [self._state, self._profile, self._dynamic]:
|
188
189
|
try:
|
@@ -208,7 +209,7 @@ class Memory:
|
|
208
209
|
elif isinstance(original_value, deque):
|
209
210
|
original_value.extend(deque(value))
|
210
211
|
else:
|
211
|
-
|
212
|
+
logger.debug(
|
212
213
|
f"Type of {type(original_value)} does not support mode `merge`, using `replace` instead!"
|
213
214
|
)
|
214
215
|
await _mem.update(key, value, store_snapshot)
|
@@ -10,6 +10,8 @@ from typing import Any, Callable, Dict, Optional, Sequence, Union
|
|
10
10
|
|
11
11
|
from .const import *
|
12
12
|
|
13
|
+
logger = logging.getLogger("pycityagent")
|
14
|
+
|
13
15
|
|
14
16
|
class MemoryUnit:
|
15
17
|
def __init__(
|
@@ -57,7 +59,7 @@ class MemoryUnit:
|
|
57
59
|
orig_v = self._content[k]
|
58
60
|
orig_type, new_type = type(orig_v), type(v)
|
59
61
|
if not orig_type == new_type:
|
60
|
-
|
62
|
+
logger.debug(
|
61
63
|
f"Type warning: The type of the value for key '{k}' is changing from `{orig_type.__name__}` to `{new_type.__name__}`!"
|
62
64
|
)
|
63
65
|
self._content.update(content)
|
@@ -82,7 +84,7 @@ class MemoryUnit:
|
|
82
84
|
await self._lock.acquire()
|
83
85
|
values = self._content[key]
|
84
86
|
if not isinstance(values, Sequence):
|
85
|
-
|
87
|
+
logger.warning(
|
86
88
|
f"the value stored in key `{key}` is not `sequence`, return value `{values}` instead!"
|
87
89
|
)
|
88
90
|
return values
|
@@ -93,7 +95,7 @@ class MemoryUnit:
|
|
93
95
|
)
|
94
96
|
top_k = len(values) if top_k is None else top_k
|
95
97
|
if len(_sorted_values_with_idx) < top_k:
|
96
|
-
|
98
|
+
logger.debug(
|
97
99
|
f"Length of values {len(_sorted_values_with_idx)} is less than top_k {top_k}, returning all values."
|
98
100
|
)
|
99
101
|
self._lock.release()
|
@@ -149,7 +151,7 @@ class MemoryBase(ABC):
|
|
149
151
|
if recent_n is None:
|
150
152
|
return _list_units
|
151
153
|
if len(_memories) < recent_n:
|
152
|
-
|
154
|
+
logger.debug(
|
153
155
|
f"Length of memory {len(_memories)} is less than recent_n {recent_n}, returning all available memories."
|
154
156
|
)
|
155
157
|
return _list_units[-recent_n:]
|
@@ -5,6 +5,7 @@ import logging
|
|
5
5
|
import math
|
6
6
|
from aiomqtt import Client
|
7
7
|
|
8
|
+
logger = logging.getLogger("pycityagent")
|
8
9
|
|
9
10
|
class Messager:
|
10
11
|
def __init__(
|
@@ -21,15 +22,15 @@ class Messager:
|
|
21
22
|
try:
|
22
23
|
await self.client.__aenter__()
|
23
24
|
self.connected = True
|
24
|
-
|
25
|
+
logger.info("Connected to MQTT Broker")
|
25
26
|
except Exception as e:
|
26
27
|
self.connected = False
|
27
|
-
|
28
|
+
logger.error(f"Failed to connect to MQTT Broker: {e}")
|
28
29
|
|
29
30
|
async def disconnect(self):
|
30
31
|
await self.client.__aexit__(None, None, None)
|
31
32
|
self.connected = False
|
32
|
-
|
33
|
+
logger.info("Disconnected from MQTT Broker")
|
33
34
|
|
34
35
|
def is_connected(self):
|
35
36
|
"""检查是否成功连接到 Broker"""
|
@@ -37,13 +38,13 @@ class Messager:
|
|
37
38
|
|
38
39
|
async def subscribe(self, topic, agent):
|
39
40
|
if not self.is_connected():
|
40
|
-
|
41
|
+
logger.error(
|
41
42
|
f"Cannot subscribe to {topic} because not connected to the Broker."
|
42
43
|
)
|
43
44
|
return
|
44
45
|
await self.client.subscribe(topic)
|
45
46
|
self.subscribers[topic] = agent
|
46
|
-
|
47
|
+
logger.info(f"Subscribed to {topic} for Agent {agent._uuid}")
|
47
48
|
|
48
49
|
async def receive_messages(self):
|
49
50
|
"""监听并将消息存入队列"""
|
@@ -61,11 +62,11 @@ class Messager:
|
|
61
62
|
"""通过 Messager 发送消息"""
|
62
63
|
message = json.dumps(payload, default=str)
|
63
64
|
await self.client.publish(topic, message)
|
64
|
-
|
65
|
+
logger.info(f"Message sent to {topic}: {message}")
|
65
66
|
|
66
67
|
async def start_listening(self):
|
67
68
|
"""启动消息监听任务"""
|
68
69
|
if self.is_connected():
|
69
70
|
asyncio.create_task(self.receive_messages())
|
70
71
|
else:
|
71
|
-
|
72
|
+
logger.error("Cannot start listening because not connected to the Broker.")
|