pycityagent 2.0.0a9__tar.gz → 2.0.0a11__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.
Files changed (70) hide show
  1. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/PKG-INFO +1 -1
  2. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/pycityagent/agent.py +167 -76
  3. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/pycityagent/environment/simulator.py +1 -1
  4. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/pycityagent/llm/llm.py +20 -125
  5. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/pycityagent/memory/memory_base.py +1 -1
  6. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/pycityagent/memory/profile.py +1 -1
  7. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/pycityagent/memory/self_define.py +1 -1
  8. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/pycityagent/memory/state.py +1 -1
  9. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/pycityagent/memory/utils.py +1 -1
  10. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/pycityagent/message/messager.py +1 -1
  11. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/pycityagent/simulation/agentgroup.py +8 -5
  12. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/pycityagent/simulation/simulation.py +6 -6
  13. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/pyproject.toml +1 -1
  14. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/README.md +0 -0
  15. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/pycityagent/__init__.py +0 -0
  16. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/pycityagent/economy/__init__.py +0 -0
  17. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/pycityagent/economy/econ_client.py +0 -0
  18. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/pycityagent/environment/__init__.py +0 -0
  19. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/pycityagent/environment/interact/__init__.py +0 -0
  20. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/pycityagent/environment/interact/interact.py +0 -0
  21. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/pycityagent/environment/message/__init__.py +0 -0
  22. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/pycityagent/environment/sence/__init__.py +0 -0
  23. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/pycityagent/environment/sence/static.py +0 -0
  24. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/pycityagent/environment/sidecar/__init__.py +0 -0
  25. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/pycityagent/environment/sidecar/sidecarv2.py +0 -0
  26. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/pycityagent/environment/sim/__init__.py +0 -0
  27. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/pycityagent/environment/sim/aoi_service.py +0 -0
  28. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/pycityagent/environment/sim/client.py +0 -0
  29. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/pycityagent/environment/sim/clock_service.py +0 -0
  30. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/pycityagent/environment/sim/economy_services.py +0 -0
  31. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/pycityagent/environment/sim/lane_service.py +0 -0
  32. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/pycityagent/environment/sim/light_service.py +0 -0
  33. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/pycityagent/environment/sim/person_service.py +0 -0
  34. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/pycityagent/environment/sim/road_service.py +0 -0
  35. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/pycityagent/environment/sim/sim_env.py +0 -0
  36. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/pycityagent/environment/sim/social_service.py +0 -0
  37. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/pycityagent/environment/utils/__init__.py +0 -0
  38. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/pycityagent/environment/utils/base64.py +0 -0
  39. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/pycityagent/environment/utils/const.py +0 -0
  40. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/pycityagent/environment/utils/geojson.py +0 -0
  41. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/pycityagent/environment/utils/grpc.py +0 -0
  42. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/pycityagent/environment/utils/map_utils.py +0 -0
  43. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/pycityagent/environment/utils/port.py +0 -0
  44. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/pycityagent/environment/utils/protobuf.py +0 -0
  45. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/pycityagent/llm/__init__.py +0 -0
  46. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/pycityagent/llm/embedding.py +0 -0
  47. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/pycityagent/llm/llmconfig.py +0 -0
  48. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/pycityagent/llm/utils.py +0 -0
  49. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/pycityagent/memory/__init__.py +0 -0
  50. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/pycityagent/memory/const.py +0 -0
  51. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/pycityagent/memory/memory.py +0 -0
  52. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/pycityagent/message/__init__.py +0 -0
  53. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/pycityagent/simulation/__init__.py +0 -0
  54. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/pycityagent/simulation/interview.py +0 -0
  55. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/pycityagent/simulation/survey/__init__.py +0 -0
  56. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/pycityagent/simulation/survey/manager.py +0 -0
  57. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/pycityagent/simulation/survey/models.py +0 -0
  58. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/pycityagent/simulation/ui/__init__.py +0 -0
  59. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/pycityagent/simulation/ui/interface.py +0 -0
  60. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/pycityagent/utils/__init__.py +0 -0
  61. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/pycityagent/utils/decorators.py +0 -0
  62. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/pycityagent/utils/parsers/__init__.py +0 -0
  63. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/pycityagent/utils/parsers/code_block_parser.py +0 -0
  64. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/pycityagent/utils/parsers/json_parser.py +0 -0
  65. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/pycityagent/utils/parsers/parser_base.py +0 -0
  66. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/pycityagent/workflow/__init__.py +0 -0
  67. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/pycityagent/workflow/block.py +0 -0
  68. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/pycityagent/workflow/prompt.py +0 -0
  69. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/pycityagent/workflow/tool.py +0 -0
  70. {pycityagent-2.0.0a9 → pycityagent-2.0.0a11}/pycityagent/workflow/trigger.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pycityagent
3
- Version: 2.0.0a9
3
+ Version: 2.0.0a11
4
4
  Summary: LLM-based城市环境agent构建库
5
5
  License: MIT
6
6
  Author: Yuwei Yan
@@ -2,10 +2,13 @@
2
2
 
3
3
  from abc import ABC, abstractmethod
4
4
  import asyncio
5
+ from uuid import UUID
5
6
  from copy import deepcopy
6
7
  from datetime import datetime
7
8
  from enum import Enum
8
9
  import logging
10
+ import random
11
+ import uuid
9
12
  from typing import Dict, List, Optional
10
13
 
11
14
  from pycityagent.environment.sim.person_service import PersonService
@@ -62,6 +65,7 @@ class Agent(ABC):
62
65
  """
63
66
  self._name = name
64
67
  self._type = type
68
+ self._uuid = uuid.uuid4()
65
69
  self._llm_client = llm_client
66
70
  self._economy_client = economy_client
67
71
  self._messager = messager
@@ -80,10 +84,6 @@ class Agent(ABC):
80
84
  del state["_llm_client"]
81
85
  return state
82
86
 
83
- async def bind_to_simulator(self):
84
- await self._bind_to_simulator()
85
- await self._bind_to_economy()
86
-
87
87
  def set_messager(self, messager: Messager):
88
88
  """
89
89
  Set the messager of the agent.
@@ -114,83 +114,12 @@ class Agent(ABC):
114
114
  """
115
115
  self._memory = memory
116
116
 
117
- def set_exp_id(self, exp_id: str):
117
+ def set_exp_id(self, exp_id: str|UUID):
118
118
  """
119
119
  Set the exp_id of the agent.
120
120
  """
121
121
  self._exp_id = exp_id
122
122
 
123
- async def _bind_to_simulator(self):
124
- """
125
- Bind Agent to Simulator
126
-
127
- Args:
128
- person_template (dict, optional): The person template in dict format. Defaults to PersonService.default_dict_person().
129
- """
130
- if self._simulator is None:
131
- logging.warning("Simulator is not set")
132
- return
133
- if not self._has_bound_to_simulator:
134
- FROM_MEMORY_KEYS = {
135
- "attribute",
136
- "home",
137
- "work",
138
- "vehicle_attribute",
139
- "bus_attribute",
140
- "pedestrian_attribute",
141
- "bike_attribute",
142
- }
143
- simulator = self._simulator
144
- memory = self._memory
145
- person_id = await memory.get("id")
146
- # ATTENTION:模拟器分配的id从0开始
147
- if person_id >= 0:
148
- await simulator.get_person(person_id)
149
- logging.debug(f"Binding to Person `{person_id}` already in Simulator")
150
- else:
151
- dict_person = deepcopy(self._person_template)
152
- for _key in FROM_MEMORY_KEYS:
153
- try:
154
- _value = await memory.get(_key)
155
- if _value:
156
- dict_person[_key] = _value
157
- except KeyError as e:
158
- continue
159
- resp = await simulator.add_person(
160
- dict2pb(dict_person, person_pb2.Person())
161
- )
162
- person_id = resp["person_id"]
163
- await memory.update("id", person_id, protect_llm_read_only_fields=False)
164
- logging.debug(
165
- f"Binding to Person `{person_id}` just added to Simulator"
166
- )
167
- # 防止模拟器还没有到prepare阶段导致get_person出错
168
- self._has_bound_to_simulator = True
169
- self._agent_id = person_id
170
-
171
- async def _bind_to_economy(self):
172
- if self._economy_client is None:
173
- logging.warning("Economy client is not set")
174
- return
175
- if not self._has_bound_to_economy:
176
- if self._has_bound_to_simulator:
177
- try:
178
- await self._economy_client.remove_agents([self._agent_id])
179
- except:
180
- pass
181
- person_id = await self._memory.get("id")
182
- await self._economy_client.add_agents(
183
- {
184
- "id": person_id,
185
- "currency": await self._memory.get("currency"),
186
- }
187
- )
188
- self._has_bound_to_economy = True
189
- else:
190
- logging.debug(
191
- f"Binding to Economy before binding to Simulator, skip binding to Economy Simulator"
192
- )
193
-
194
123
  @property
195
124
  def llm(self):
196
125
  """The Agent's LLM"""
@@ -300,6 +229,9 @@ class Agent(ABC):
300
229
  async def forward(self) -> None:
301
230
  """智能体行为逻辑"""
302
231
  raise NotImplementedError
232
+
233
+ async def handle_gather_message(self, payload: str):
234
+ raise NotImplementedError
303
235
 
304
236
  async def run(self) -> None:
305
237
  """
@@ -334,6 +266,81 @@ class CitizenAgent(Agent):
334
266
  memory,
335
267
  )
336
268
 
269
+ async def bind_to_simulator(self):
270
+ await self._bind_to_simulator()
271
+ await self._bind_to_economy()
272
+
273
+ async def _bind_to_simulator(self):
274
+ """
275
+ Bind Agent to Simulator
276
+
277
+ Args:
278
+ person_template (dict, optional): The person template in dict format. Defaults to PersonService.default_dict_person().
279
+ """
280
+ if self._simulator is None:
281
+ logging.warning("Simulator is not set")
282
+ return
283
+ if not self._has_bound_to_simulator:
284
+ FROM_MEMORY_KEYS = {
285
+ "attribute",
286
+ "home",
287
+ "work",
288
+ "vehicle_attribute",
289
+ "bus_attribute",
290
+ "pedestrian_attribute",
291
+ "bike_attribute",
292
+ }
293
+ simulator = self._simulator
294
+ memory = self._memory
295
+ person_id = await memory.get("id")
296
+ # ATTENTION:模拟器分配的id从0开始
297
+ if person_id >= 0:
298
+ await simulator.get_person(person_id)
299
+ logging.debug(f"Binding to Person `{person_id}` already in Simulator")
300
+ else:
301
+ dict_person = deepcopy(self._person_template)
302
+ for _key in FROM_MEMORY_KEYS:
303
+ try:
304
+ _value = await memory.get(_key)
305
+ if _value:
306
+ dict_person[_key] = _value
307
+ except KeyError as e:
308
+ continue
309
+ resp = await simulator.add_person(
310
+ dict2pb(dict_person, person_pb2.Person())
311
+ )
312
+ person_id = resp["person_id"]
313
+ await memory.update("id", person_id, protect_llm_read_only_fields=False)
314
+ logging.debug(
315
+ f"Binding to Person `{person_id}` just added to Simulator"
316
+ )
317
+ # 防止模拟器还没有到prepare阶段导致get_person出错
318
+ self._has_bound_to_simulator = True
319
+ self._agent_id = person_id
320
+
321
+ async def _bind_to_economy(self):
322
+ if self._economy_client is None:
323
+ logging.warning("Economy client is not set")
324
+ return
325
+ if not self._has_bound_to_economy:
326
+ if self._has_bound_to_simulator:
327
+ try:
328
+ await self._economy_client.remove_agents([self._agent_id])
329
+ except:
330
+ pass
331
+ person_id = await self._memory.get("id")
332
+ await self._economy_client.add_agents(
333
+ {
334
+ "id": person_id,
335
+ "currency": await self._memory.get("currency"),
336
+ }
337
+ )
338
+ self._has_bound_to_economy = True
339
+ else:
340
+ logging.debug(
341
+ f"Binding to Economy before binding to Simulator, skip binding to Economy Simulator"
342
+ )
343
+
337
344
  async def handle_gather_message(self, payload: str):
338
345
  """处理收到的消息,识别发送者"""
339
346
  # 从消息中解析发送者 ID 和消息内容
@@ -366,6 +373,90 @@ class InstitutionAgent(Agent):
366
373
  memory,
367
374
  )
368
375
 
376
+ async def bind_to_simulator(self):
377
+ await self._bind_to_economy()
378
+
379
+ async def _bind_to_economy(self):
380
+ if self._economy_client is None:
381
+ logging.debug("Economy client is not set")
382
+ return
383
+ if not self._has_bound_to_economy:
384
+ # TODO: More general id generation
385
+ _id = random.randint(100000, 999999)
386
+ self._agent_id = _id
387
+ await self._memory.update("id", _id, protect_llm_read_only_fields=False)
388
+ try:
389
+ await self._economy_client.remove_orgs([self._agent_id])
390
+ except:
391
+ pass
392
+ try:
393
+ id = await self._memory.get("id")
394
+ type = await self._memory.get("type")
395
+ try:
396
+ nominal_gdp = await self._memory.get("nominal_gdp")
397
+ except:
398
+ nominal_gdp = []
399
+ try:
400
+ real_gdp = await self._memory.get("real_gdp")
401
+ except:
402
+ real_gdp = []
403
+ try:
404
+ unemployment = await self._memory.get("unemployment")
405
+ except:
406
+ unemployment = []
407
+ try:
408
+ wages = await self._memory.get("wages")
409
+ except:
410
+ wages = []
411
+ try:
412
+ prices = await self._memory.get("prices")
413
+ except:
414
+ prices = []
415
+ try:
416
+ inventory = await self._memory.get("inventory")
417
+ except:
418
+ inventory = 0
419
+ try:
420
+ price = await self._memory.get("price")
421
+ except:
422
+ price = 0
423
+ try:
424
+ currency = await self._memory.get("currency")
425
+ except:
426
+ currency = 0.0
427
+ try:
428
+ interest_rate = await self._memory.get("interest_rate")
429
+ except:
430
+ interest_rate = 0.0
431
+ try:
432
+ bracket_cutoffs = await self._memory.get("bracket_cutoffs")
433
+ except:
434
+ bracket_cutoffs = []
435
+ try:
436
+ bracket_rates = await self._memory.get("bracket_rates")
437
+ except:
438
+ bracket_rates = []
439
+ await self._economy_client.add_orgs(
440
+ {
441
+ "id": id,
442
+ "type": type,
443
+ "nominal_gdp": nominal_gdp,
444
+ "real_gdp": real_gdp,
445
+ "unemployment": unemployment,
446
+ "wages": wages,
447
+ "prices": prices,
448
+ "inventory": inventory,
449
+ "price": price,
450
+ "currency": currency,
451
+ "interest_rate": interest_rate,
452
+ "bracket_cutoffs": bracket_cutoffs,
453
+ "bracket_rates": bracket_rates,
454
+ }
455
+ )
456
+ except Exception as e:
457
+ logging.error(f"Failed to bind to Economy: {e}")
458
+ self._has_bound_to_economy = True
459
+
369
460
  async def handle_gather_message(self, payload: str):
370
461
  """处理收到的消息,识别发送者"""
371
462
  # 从消息中解析发送者 ID 和消息内容
@@ -3,7 +3,6 @@
3
3
  import asyncio
4
4
  import logging
5
5
  import os
6
- from collections import defaultdict
7
6
  from collections.abc import Sequence
8
7
  from datetime import datetime, timedelta
9
8
  from typing import Any, Optional, Tuple, Union, cast
@@ -191,6 +190,7 @@ class Simulator:
191
190
  formatted_time = current_time.strftime(format)
192
191
  return formatted_time
193
192
  else:
193
+ # BUG: 返回的time是float类型
194
194
  return t_sec["t"]
195
195
 
196
196
  async def get_person(self, person_id: int) -> dict:
@@ -15,7 +15,6 @@ from dashscope import ImageSynthesis
15
15
  from PIL import Image
16
16
  from io import BytesIO
17
17
  from typing import Any, Optional, Union, List, Dict
18
- import aiohttp
19
18
  from .llmconfig import *
20
19
  from .utils import *
21
20
 
@@ -45,7 +44,13 @@ class LLM:
45
44
  elif self.config.text["request_type"] == "deepseek":
46
45
  self._aclient = AsyncOpenAI(
47
46
  api_key=self.config.text["api_key"],
48
- base_url="https://api.deepseek.com/beta",
47
+ base_url="https://api.deepseek.com/v1",
48
+ timeout=300,
49
+ )
50
+ elif self.config.text["request_type"] == "qwen":
51
+ self._aclient = AsyncOpenAI(
52
+ api_key=self.config.text["api_key"],
53
+ base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
49
54
  timeout=300,
50
55
  )
51
56
  elif self.config.text["request_type"] == "zhipuai":
@@ -102,106 +107,6 @@ Token Usage:
102
107
  "ratio": rate,
103
108
  }
104
109
 
105
- def text_request(
106
- self,
107
- dialog: Any,
108
- temperature: float = 1,
109
- max_tokens: Optional[int] = None,
110
- top_p: Optional[float] = None,
111
- frequency_penalty: Optional[float] = None,
112
- presence_penalty: Optional[float] = None,
113
- tools: Optional[List[Dict[str, Any]]] = None,
114
- tool_choice: Optional[Dict[str, Any]] = None,
115
- ) -> Optional[str]:
116
- """
117
- 文本相关请求
118
- Text request
119
-
120
- Args:
121
- - dialog (list[dict]): 标准的LLM文本dialog. The standard text LLM dialog
122
- - temperature (float): default 1, used in openai
123
- - max_tokens (int): default None, used in openai
124
- - top_p (float): default None, used in openai
125
- - frequency_penalty (float): default None, used in openai
126
- - presence_penalty (float): default None, used in openai
127
-
128
- Returns:
129
- - (str): the response content
130
- """
131
- if "api_base" in self.config.text.keys():
132
- api_base = self.config.text["api_base"]
133
- else:
134
- api_base = None
135
- if self.config.text["request_type"] == "openai":
136
- client = OpenAI(
137
- api_key=self.config.text["api_key"],
138
- base_url=api_base,
139
- )
140
- response = client.chat.completions.create(
141
- model=self.config.text["model"],
142
- messages=dialog,
143
- temperature=temperature,
144
- max_tokens=max_tokens,
145
- top_p=top_p,
146
- frequency_penalty=frequency_penalty,
147
- presence_penalty=presence_penalty,
148
- tools=tools,
149
- tool_choice=tool_choice,
150
- )
151
- self.prompt_tokens_used += response.usage.prompt_tokens # type: ignore
152
- self.completion_tokens_used += response.usage.completion_tokens # type: ignore
153
- self.request_number += 1
154
- if tools != None:
155
- return response.tool_calls[0].function.arguments
156
- else:
157
- return response.choices[0].message.content
158
- elif self.config.text["request_type"] == "qwen":
159
- response = dashscope.Generation.call(
160
- model=self.config.text["model"],
161
- api_key=self.config.text["api_key"],
162
- messages=dialog,
163
- result_format="message",
164
- )
165
- if response.status_code == HTTPStatus.OK: # type: ignore
166
- return response.output.choices[0]["message"]["content"] # type: ignore
167
- else:
168
- return "Error: {}, {}".format(response.status_code, response.message) # type: ignore
169
- elif self.config.text["request_type"] == "deepseek":
170
- client = OpenAI(
171
- api_key=self.config.text["api_key"],
172
- base_url="https://api.deepseek.com/beta",
173
- )
174
- response = client.chat.completions.create(
175
- model=self.config.text["model"],
176
- messages=dialog,
177
- temperature=temperature,
178
- max_tokens=max_tokens,
179
- top_p=top_p,
180
- frequency_penalty=frequency_penalty,
181
- presence_penalty=presence_penalty,
182
- stream=False,
183
- )
184
- self.prompt_tokens_used += response.usage.prompt_tokens # type: ignore
185
- self.completion_tokens_used += response.usage.completion_tokens # type: ignore
186
- self.request_number += 1
187
- return response.choices[0].message.content
188
- elif self.config.text["request_type"] == "zhipuai":
189
- client = ZhipuAI(api_key=self.config.text["api_key"])
190
- response = client.chat.completions.create(
191
- model=self.config.text["model"],
192
- messages=dialog,
193
- temperature=temperature,
194
- top_p=top_p,
195
- stream=False,
196
- )
197
- self.prompt_tokens_used += response.usage.prompt_tokens # type: ignore
198
- self.completion_tokens_used += response.usage.completion_tokens # type: ignore
199
- self.request_number += 1
200
- return response.choices[0].message.content # type: ignore
201
- else:
202
- print("ERROR: Wrong Config")
203
- return "wrong config"
204
-
205
110
  async def atext_request(
206
111
  self,
207
112
  dialog: Any,
@@ -221,6 +126,7 @@ Token Usage:
221
126
  if (
222
127
  self.config.text["request_type"] == "openai"
223
128
  or self.config.text["request_type"] == "deepseek"
129
+ or self.config.text["request_type"] == "qwen"
224
130
  ):
225
131
  for attempt in range(retries):
226
132
  try:
@@ -242,8 +148,12 @@ Token Usage:
242
148
  self.prompt_tokens_used += response.usage.prompt_tokens # type: ignore
243
149
  self.completion_tokens_used += response.usage.completion_tokens # type: ignore
244
150
  self.request_number += 1
245
- if tools != None:
246
- return response.tool_calls[0].function.arguments
151
+ if tools and response.choices[0].message.tool_calls:
152
+ return json.loads(
153
+ response.choices[0]
154
+ .message.tool_calls[0]
155
+ .function.arguments
156
+ )
247
157
  else:
248
158
  return response.choices[0].message.content
249
159
  else:
@@ -263,8 +173,12 @@ Token Usage:
263
173
  self.prompt_tokens_used += response.usage.prompt_tokens # type: ignore
264
174
  self.completion_tokens_used += response.usage.completion_tokens # type: ignore
265
175
  self.request_number += 1
266
- if tools != None:
267
- return response.tool_calls[0].function.arguments
176
+ if tools and response.choices[0].message.tool_calls:
177
+ return json.loads(
178
+ response.choices[0]
179
+ .message.tool_calls[0]
180
+ .function.arguments
181
+ )
268
182
  else:
269
183
  return response.choices[0].message.content
270
184
  except APIConnectionError as e:
@@ -327,25 +241,6 @@ Token Usage:
327
241
  await asyncio.sleep(2**attempt)
328
242
  else:
329
243
  raise e
330
- elif self.config.text["request_type"] == "qwen":
331
- async with aiohttp.ClientSession() as session:
332
- api_url = "https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation"
333
- headers = {
334
- "Content-Type": "application/json",
335
- "Authorization": f"{self.config.text['api_key']}",
336
- }
337
- payload = {
338
- "model": self.config.text["model"],
339
- "input": {"messages": dialog},
340
- }
341
- async with session.post(api_url, json=payload, headers=headers) as resp:
342
- response_json = await resp.json()
343
- if "code" in response_json.keys():
344
- raise Exception(
345
- f"Error: {response_json['code']}, {response_json['message']}"
346
- )
347
- else:
348
- return response_json["output"]["text"]
349
244
  else:
350
245
  print("ERROR: Wrong Config")
351
246
  return "wrong config"
@@ -6,7 +6,7 @@ import asyncio
6
6
  import logging
7
7
  import time
8
8
  from abc import ABC, abstractmethod
9
- from typing import Any, Callable, Dict, Iterable, List, Optional, Sequence, Tuple, Union
9
+ from typing import Any, Callable, Dict, Optional, Sequence, Union
10
10
 
11
11
  from .const import *
12
12
 
@@ -3,7 +3,7 @@ Agent Profile
3
3
  """
4
4
 
5
5
  from copy import deepcopy
6
- from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, Union, cast
6
+ from typing import Any, Callable, Dict, Optional, Sequence, Union, cast
7
7
 
8
8
  from ..utils.decorators import lock_decorator
9
9
  from .const import *
@@ -3,7 +3,7 @@ Self Define Data
3
3
  """
4
4
 
5
5
  from copy import deepcopy
6
- from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, Union, cast
6
+ from typing import Any, Callable, Dict, Optional, Sequence, Union, cast
7
7
 
8
8
  from ..utils.decorators import lock_decorator
9
9
  from .const import *
@@ -3,7 +3,7 @@ Agent State
3
3
  """
4
4
 
5
5
  from copy import deepcopy
6
- from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, Union, cast
6
+ from typing import Any, Callable, Dict, Optional, Sequence, Union, cast
7
7
 
8
8
  from ..utils.decorators import lock_decorator
9
9
  from .const import *
@@ -1,4 +1,4 @@
1
- from typing import Any, Dict, List, Optional, Sequence, Tuple, Union
1
+ from typing import Any, Sequence, Union
2
2
 
3
3
  from .memory_base import MemoryUnit
4
4
 
@@ -7,7 +7,7 @@ from aiomqtt import Client
7
7
 
8
8
  class Messager:
9
9
  def __init__(
10
- self, hostname, port=1883, username=None, password=None, timeout=math.inf
10
+ self, hostname:str, port:int=1883, username=None, password=None, timeout=math.inf
11
11
  ):
12
12
  self.client = Client(
13
13
  hostname, port=port, username=username, password=password, timeout=timeout
@@ -1,17 +1,18 @@
1
1
  import asyncio
2
2
  import logging
3
3
  import ray
4
+ from uuid import UUID
4
5
  from pycityagent.agent import Agent
5
6
  from pycityagent.economy.econ_client import EconomyClient
6
7
  from pycityagent.environment.simulator import Simulator
7
8
  from pycityagent.llm.llm import LLM
8
9
  from pycityagent.llm.llmconfig import LLMConfig
9
10
  from pycityagent.message import Messager
10
-
11
+ from typing import Any
11
12
 
12
13
  @ray.remote
13
14
  class AgentGroup:
14
- def __init__(self, agents: list[Agent], config: dict, exp_id: str):
15
+ def __init__(self, agents: list[Agent], config: dict, exp_id: str|UUID):
15
16
  self.agents = agents
16
17
  self.config = config
17
18
  self.exp_id = exp_id
@@ -45,7 +46,8 @@ class AgentGroup:
45
46
  agent.set_exp_id(self.exp_id)
46
47
  agent.set_llm_client(self.llm)
47
48
  agent.set_simulator(self.simulator)
48
- agent.set_economy_client(self.economy_client)
49
+ if self.economy_client is not None:
50
+ agent.set_economy_client(self.economy_client)
49
51
  agent.set_messager(self.messager)
50
52
 
51
53
  async def init_agents(self):
@@ -69,7 +71,7 @@ class AgentGroup:
69
71
  results[agent._agent_id] = await agent.memory.get(content)
70
72
  return results
71
73
 
72
- async def update(self, target_agent_id: str, target_key: str, content: any):
74
+ async def update(self, target_agent_id: str, target_key: str, content: Any):
73
75
  agent = self.id2agent[target_agent_id]
74
76
  await agent.memory.update(target_key, content)
75
77
 
@@ -123,14 +125,15 @@ class AgentGroup:
123
125
  try:
124
126
  # 获取开始时间
125
127
  start_time = await self.simulator.get_time()
128
+ start_time = int(start_time)
126
129
  # 计算结束时间(秒)
127
130
  end_time = start_time + day * 24 * 3600 # 将天数转换为秒
128
131
 
129
132
  while True:
130
133
  current_time = await self.simulator.get_time()
134
+ current_time = int(current_time)
131
135
  if current_time >= end_time:
132
136
  break
133
-
134
137
  await self.step()
135
138
 
136
139
  except Exception as e:
@@ -4,7 +4,7 @@ import logging
4
4
  import uuid
5
5
  from datetime import datetime
6
6
  import random
7
- from typing import Dict, List, Optional, Callable, Union
7
+ from typing import Dict, List, Optional, Callable, Union,Any
8
8
  from mosstool.map._map_util.const import AOI_START_ID
9
9
 
10
10
  from pycityagent.memory.memory import Memory
@@ -41,7 +41,7 @@ class AgentSimulation:
41
41
  self.config = config
42
42
  self.agent_prefix = agent_prefix
43
43
  self._agents: Dict[str, Agent] = {}
44
- self._groups: Dict[str, AgentGroup] = {}
44
+ self._groups: Dict[str, AgentGroup] = {} # type:ignore
45
45
  self._interview_manager = InterviewManager()
46
46
  self._interview_lock = asyncio.Lock()
47
47
  self._start_time = datetime.now()
@@ -50,14 +50,14 @@ class AgentSimulation:
50
50
  self._loop = asyncio.get_event_loop()
51
51
  self._blocked_agents: List[str] = [] # 新增:持续阻塞的智能体列表
52
52
  self._survey_manager = SurveyManager()
53
- self._agentid2group: Dict[str, AgentGroup] = {}
53
+ self._agentid2group: Dict[str, AgentGroup] = {}# type:ignore
54
54
  self._agent_ids: List[str] = []
55
55
 
56
56
  async def init_agents(
57
57
  self,
58
58
  agent_count: Union[int, list[int]],
59
59
  group_size: int = 1000,
60
- memory_config_func: Union[Callable, list[Callable]] = None,
60
+ memory_config_func: Optional[Union[Callable, list[Callable]]] = None,
61
61
  ) -> None:
62
62
  """初始化智能体
63
63
 
@@ -139,13 +139,13 @@ class AgentSimulation:
139
139
  self._agentid2group[agent_id] = group
140
140
 
141
141
  async def gather(self, content: str):
142
- """收集所有智能体的ID"""
142
+ """收集智能体的特定信息"""
143
143
  gather_tasks = []
144
144
  for group in self._groups.values():
145
145
  gather_tasks.append(group.gather.remote(content))
146
146
  return await asyncio.gather(*gather_tasks)
147
147
 
148
- async def update(self, target_agent_id: str, target_key: str, content: any):
148
+ async def update(self, target_agent_id: str, target_key: str, content: Any):
149
149
  """更新指定智能体的记忆"""
150
150
  group = self._agentid2group[target_agent_id]
151
151
  await group.update.remote(target_agent_id, target_key, content)
@@ -3,7 +3,7 @@ in-project = true
3
3
 
4
4
  [tool.poetry]
5
5
  name = "pycityagent"
6
- version = "2.0.0a9"
6
+ version = "2.0.0a11"
7
7
  description = "LLM-based城市环境agent构建库"
8
8
  authors = ["Yuwei Yan <pinkgranite86@gmail.com>","Junbo Yan <yanjb20thu@gmali.com>"]
9
9
  license = "MIT"
File without changes