pycityagent 2.0.0a8__tar.gz → 2.0.0a10__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.0a8 → pycityagent-2.0.0a10}/PKG-INFO +2 -2
  2. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/pycityagent/agent.py +135 -8
  3. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/pycityagent/environment/simulator.py +0 -1
  4. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/pycityagent/llm/llm.py +20 -125
  5. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/pycityagent/memory/memory_base.py +1 -1
  6. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/pycityagent/memory/profile.py +1 -1
  7. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/pycityagent/memory/self_define.py +1 -1
  8. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/pycityagent/memory/state.py +1 -1
  9. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/pycityagent/memory/utils.py +1 -1
  10. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/pycityagent/message/messager.py +1 -1
  11. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/pycityagent/simulation/agentgroup.py +8 -5
  12. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/pycityagent/simulation/simulation.py +6 -6
  13. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/pyproject.toml +2 -2
  14. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/README.md +0 -0
  15. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/pycityagent/__init__.py +0 -0
  16. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/pycityagent/economy/__init__.py +0 -0
  17. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/pycityagent/economy/econ_client.py +0 -0
  18. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/pycityagent/environment/__init__.py +0 -0
  19. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/pycityagent/environment/interact/__init__.py +0 -0
  20. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/pycityagent/environment/interact/interact.py +0 -0
  21. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/pycityagent/environment/message/__init__.py +0 -0
  22. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/pycityagent/environment/sence/__init__.py +0 -0
  23. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/pycityagent/environment/sence/static.py +0 -0
  24. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/pycityagent/environment/sidecar/__init__.py +0 -0
  25. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/pycityagent/environment/sidecar/sidecarv2.py +0 -0
  26. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/pycityagent/environment/sim/__init__.py +0 -0
  27. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/pycityagent/environment/sim/aoi_service.py +0 -0
  28. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/pycityagent/environment/sim/client.py +0 -0
  29. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/pycityagent/environment/sim/clock_service.py +0 -0
  30. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/pycityagent/environment/sim/economy_services.py +0 -0
  31. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/pycityagent/environment/sim/lane_service.py +0 -0
  32. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/pycityagent/environment/sim/light_service.py +0 -0
  33. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/pycityagent/environment/sim/person_service.py +0 -0
  34. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/pycityagent/environment/sim/road_service.py +0 -0
  35. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/pycityagent/environment/sim/sim_env.py +0 -0
  36. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/pycityagent/environment/sim/social_service.py +0 -0
  37. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/pycityagent/environment/utils/__init__.py +0 -0
  38. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/pycityagent/environment/utils/base64.py +0 -0
  39. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/pycityagent/environment/utils/const.py +0 -0
  40. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/pycityagent/environment/utils/geojson.py +0 -0
  41. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/pycityagent/environment/utils/grpc.py +0 -0
  42. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/pycityagent/environment/utils/map_utils.py +0 -0
  43. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/pycityagent/environment/utils/port.py +0 -0
  44. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/pycityagent/environment/utils/protobuf.py +0 -0
  45. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/pycityagent/llm/__init__.py +0 -0
  46. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/pycityagent/llm/embedding.py +0 -0
  47. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/pycityagent/llm/llmconfig.py +0 -0
  48. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/pycityagent/llm/utils.py +0 -0
  49. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/pycityagent/memory/__init__.py +0 -0
  50. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/pycityagent/memory/const.py +0 -0
  51. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/pycityagent/memory/memory.py +0 -0
  52. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/pycityagent/message/__init__.py +0 -0
  53. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/pycityagent/simulation/__init__.py +0 -0
  54. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/pycityagent/simulation/interview.py +0 -0
  55. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/pycityagent/simulation/survey/__init__.py +0 -0
  56. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/pycityagent/simulation/survey/manager.py +0 -0
  57. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/pycityagent/simulation/survey/models.py +0 -0
  58. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/pycityagent/simulation/ui/__init__.py +0 -0
  59. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/pycityagent/simulation/ui/interface.py +0 -0
  60. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/pycityagent/utils/__init__.py +0 -0
  61. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/pycityagent/utils/decorators.py +0 -0
  62. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/pycityagent/utils/parsers/__init__.py +0 -0
  63. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/pycityagent/utils/parsers/code_block_parser.py +0 -0
  64. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/pycityagent/utils/parsers/json_parser.py +0 -0
  65. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/pycityagent/utils/parsers/parser_base.py +0 -0
  66. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/pycityagent/workflow/__init__.py +0 -0
  67. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/pycityagent/workflow/block.py +0 -0
  68. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/pycityagent/workflow/prompt.py +0 -0
  69. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/pycityagent/workflow/tool.py +0 -0
  70. {pycityagent-2.0.0a8 → pycityagent-2.0.0a10}/pycityagent/workflow/trigger.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pycityagent
3
- Version: 2.0.0a8
3
+ Version: 2.0.0a10
4
4
  Summary: LLM-based城市环境agent构建库
5
5
  License: MIT
6
6
  Author: Yuwei Yan
@@ -27,7 +27,7 @@ Requires-Dist: matplotlib (==3.8.3)
27
27
  Requires-Dist: mosstool (==1.0.24)
28
28
  Requires-Dist: networkx (==3.2.1)
29
29
  Requires-Dist: numpy (>=1.20.0,<2.0.0)
30
- Requires-Dist: openai (==1.54.3)
30
+ Requires-Dist: openai (>=1.58.1,<2.0.0)
31
31
  Requires-Dist: poetry (>=1.2.2)
32
32
  Requires-Dist: protobuf (<=4.24.0)
33
33
  Requires-Dist: pycitydata (==1.0.0)
@@ -2,10 +2,12 @@
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
9
11
  from typing import Dict, List, Optional
10
12
 
11
13
  from pycityagent.environment.sim.person_service import PersonService
@@ -80,10 +82,6 @@ class Agent(ABC):
80
82
  del state["_llm_client"]
81
83
  return state
82
84
 
83
- async def bind_to_simulator(self):
84
- await self._bind_to_simulator()
85
- await self._bind_to_economy()
86
-
87
85
  def set_messager(self, messager: Messager):
88
86
  """
89
87
  Set the messager of the agent.
@@ -114,7 +112,7 @@ class Agent(ABC):
114
112
  """
115
113
  self._memory = memory
116
114
 
117
- def set_exp_id(self, exp_id: str):
115
+ def set_exp_id(self, exp_id: str|UUID):
118
116
  """
119
117
  Set the exp_id of the agent.
120
118
  """
@@ -141,7 +139,7 @@ class Agent(ABC):
141
139
  "bike_attribute",
142
140
  }
143
141
  simulator = self._simulator
144
- memory = self._memory
142
+ memory = self.memory
145
143
  person_id = await memory.get("id")
146
144
  # ATTENTION:模拟器分配的id从0开始
147
145
  if person_id >= 0:
@@ -178,11 +176,11 @@ class Agent(ABC):
178
176
  await self._economy_client.remove_agents([self._agent_id])
179
177
  except:
180
178
  pass
181
- person_id = await self._memory.get("id")
179
+ person_id = await self.memory.get("id")
182
180
  await self._economy_client.add_agents(
183
181
  {
184
182
  "id": person_id,
185
- "currency": await self._memory.get("currency"),
183
+ "currency": await self.memory.get("currency"),
186
184
  }
187
185
  )
188
186
  self._has_bound_to_economy = True
@@ -300,6 +298,9 @@ class Agent(ABC):
300
298
  async def forward(self) -> None:
301
299
  """智能体行为逻辑"""
302
300
  raise NotImplementedError
301
+
302
+ async def handle_gather_message(self, payload: str):
303
+ raise NotImplementedError
303
304
 
304
305
  async def run(self) -> None:
305
306
  """
@@ -334,6 +335,81 @@ class CitizenAgent(Agent):
334
335
  memory,
335
336
  )
336
337
 
338
+ async def bind_to_simulator(self):
339
+ await self._bind_to_simulator()
340
+ await self._bind_to_economy()
341
+
342
+ async def _bind_to_simulator(self):
343
+ """
344
+ Bind Agent to Simulator
345
+
346
+ Args:
347
+ person_template (dict, optional): The person template in dict format. Defaults to PersonService.default_dict_person().
348
+ """
349
+ if self._simulator is None:
350
+ logging.warning("Simulator is not set")
351
+ return
352
+ if not self._has_bound_to_simulator:
353
+ FROM_MEMORY_KEYS = {
354
+ "attribute",
355
+ "home",
356
+ "work",
357
+ "vehicle_attribute",
358
+ "bus_attribute",
359
+ "pedestrian_attribute",
360
+ "bike_attribute",
361
+ }
362
+ simulator = self._simulator
363
+ memory = self._memory
364
+ person_id = await memory.get("id")
365
+ # ATTENTION:模拟器分配的id从0开始
366
+ if person_id >= 0:
367
+ await simulator.get_person(person_id)
368
+ logging.debug(f"Binding to Person `{person_id}` already in Simulator")
369
+ else:
370
+ dict_person = deepcopy(self._person_template)
371
+ for _key in FROM_MEMORY_KEYS:
372
+ try:
373
+ _value = await memory.get(_key)
374
+ if _value:
375
+ dict_person[_key] = _value
376
+ except KeyError as e:
377
+ continue
378
+ resp = await simulator.add_person(
379
+ dict2pb(dict_person, person_pb2.Person())
380
+ )
381
+ person_id = resp["person_id"]
382
+ await memory.update("id", person_id, protect_llm_read_only_fields=False)
383
+ logging.debug(
384
+ f"Binding to Person `{person_id}` just added to Simulator"
385
+ )
386
+ # 防止模拟器还没有到prepare阶段导致get_person出错
387
+ self._has_bound_to_simulator = True
388
+ self._agent_id = person_id
389
+
390
+ async def _bind_to_economy(self):
391
+ if self._economy_client is None:
392
+ logging.warning("Economy client is not set")
393
+ return
394
+ if not self._has_bound_to_economy:
395
+ if self._has_bound_to_simulator:
396
+ try:
397
+ await self._economy_client.remove_agents([self._agent_id])
398
+ except:
399
+ pass
400
+ person_id = await self._memory.get("id")
401
+ await self._economy_client.add_agents(
402
+ {
403
+ "id": person_id,
404
+ "currency": await self._memory.get("currency"),
405
+ }
406
+ )
407
+ self._has_bound_to_economy = True
408
+ else:
409
+ logging.debug(
410
+ f"Binding to Economy before binding to Simulator, skip binding to Economy Simulator"
411
+ )
412
+
337
413
  async def handle_gather_message(self, payload: str):
338
414
  """处理收到的消息,识别发送者"""
339
415
  # 从消息中解析发送者 ID 和消息内容
@@ -366,6 +442,57 @@ class InstitutionAgent(Agent):
366
442
  memory,
367
443
  )
368
444
 
445
+ async def bind_to_simulator(self):
446
+ await self._bind_to_economy()
447
+
448
+ async def _bind_to_economy(self):
449
+ if self._economy_client is None:
450
+ logging.debug("Economy client is not set")
451
+ return
452
+ if not self._has_bound_to_economy:
453
+ # TODO: More general id generation
454
+ _id = random.randint(100000, 999999)
455
+ self._agent_id = _id
456
+ await self._memory.update("id", _id, protect_llm_read_only_fields=False)
457
+ try:
458
+ await self._economy_client.remove_agents([self._agent_id])
459
+ except:
460
+ pass
461
+ try:
462
+ id = await self._memory.get("id")
463
+ type = await self._memory.get("type")
464
+ nominal_gdp = await self._memory.get("nominal_gdp")
465
+ real_gdp = await self._memory.get("real_gdp")
466
+ unemployment = await self._memory.get("unemployment")
467
+ wages = await self._memory.get("wages")
468
+ prices = await self._memory.get("prices")
469
+ inventory = await self._memory.get("inventory")
470
+ price = await self._memory.get("price")
471
+ currency = await self._memory.get("currency")
472
+ interest_rate = await self._memory.get("interest_rate")
473
+ bracket_cutoffs = await self._memory.get("bracket_cutoffs")
474
+ bracket_rates = await self._memory.get("bracket_rates")
475
+ await self._economy_client.add_orgs(
476
+ {
477
+ "id": id,
478
+ "type": type,
479
+ "currency": currency,
480
+ "nominal_gdp": nominal_gdp,
481
+ "real_gdp": real_gdp,
482
+ "unemployment": unemployment,
483
+ "wages": wages,
484
+ "prices": prices,
485
+ "inventory": inventory,
486
+ "price": price,
487
+ "interest_rate": interest_rate,
488
+ "bracket_cutoffs": bracket_cutoffs,
489
+ "bracket_rates": bracket_rates,
490
+ }
491
+ )
492
+ except Exception as e:
493
+ logging.error(f"Failed to bind to Economy: {e}")
494
+ self._has_bound_to_economy = True
495
+
369
496
  async def handle_gather_message(self, payload: str):
370
497
  """处理收到的消息,识别发送者"""
371
498
  # 从消息中解析发送者 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
@@ -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
+ assert type(start_time)==int
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
+ assert type(current_time)==int
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.0a8"
6
+ version = "2.0.0a10"
7
7
  description = "LLM-based城市环境agent构建库"
8
8
  authors = ["Yuwei Yan <pinkgranite86@gmail.com>","Junbo Yan <yanjb20thu@gmali.com>"]
9
9
  license = "MIT"
@@ -28,7 +28,7 @@ grpcio = "1.67.1"
28
28
  matplotlib = "3.8.3"
29
29
  networkx = "3.2.1"
30
30
  numpy = "^1.20.0"
31
- openai = "1.54.3"
31
+ openai = "^1.58.1"
32
32
  Pillow = "11.0.0"
33
33
  protobuf = "<=4.24.0,<5.0.0"
34
34
  pycitydata = "1.0.0"
File without changes