pycityagent 2.0.0a9__py3-none-any.whl → 2.0.0a11__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pycityagent/agent.py +167 -76
- pycityagent/environment/simulator.py +1 -1
- pycityagent/llm/llm.py +20 -125
- pycityagent/memory/memory_base.py +1 -1
- pycityagent/memory/profile.py +1 -1
- pycityagent/memory/self_define.py +1 -1
- pycityagent/memory/state.py +1 -1
- pycityagent/memory/utils.py +1 -1
- pycityagent/message/messager.py +1 -1
- pycityagent/simulation/agentgroup.py +8 -5
- pycityagent/simulation/simulation.py +6 -6
- {pycityagent-2.0.0a9.dist-info → pycityagent-2.0.0a11.dist-info}/METADATA +1 -1
- {pycityagent-2.0.0a9.dist-info → pycityagent-2.0.0a11.dist-info}/RECORD +14 -14
- {pycityagent-2.0.0a9.dist-info → pycityagent-2.0.0a11.dist-info}/WHEEL +0 -0
pycityagent/agent.py
CHANGED
@@ -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:
|
pycityagent/llm/llm.py
CHANGED
@@ -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/
|
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
|
246
|
-
return
|
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
|
267
|
-
return
|
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,
|
9
|
+
from typing import Any, Callable, Dict, Optional, Sequence, Union
|
10
10
|
|
11
11
|
from .const import *
|
12
12
|
|
pycityagent/memory/profile.py
CHANGED
@@ -3,7 +3,7 @@ Agent Profile
|
|
3
3
|
"""
|
4
4
|
|
5
5
|
from copy import deepcopy
|
6
|
-
from typing import Any, Callable, Dict,
|
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,
|
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 *
|
pycityagent/memory/state.py
CHANGED
@@ -3,7 +3,7 @@ Agent State
|
|
3
3
|
"""
|
4
4
|
|
5
5
|
from copy import deepcopy
|
6
|
-
from typing import Any, Callable, Dict,
|
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 *
|
pycityagent/memory/utils.py
CHANGED
pycityagent/message/messager.py
CHANGED
@@ -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
|
-
|
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:
|
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
|
-
"""
|
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:
|
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)
|
@@ -1,5 +1,5 @@
|
|
1
1
|
pycityagent/__init__.py,sha256=n56bWkAUEcvjDsb7LcJpaGjlrriSKPnR0yBhwRfEYBA,212
|
2
|
-
pycityagent/agent.py,sha256=
|
2
|
+
pycityagent/agent.py,sha256=84xdcX_W9DGzrjl_0yp53RwUuUrcMjL9ZdCMJY563k8,15675
|
3
3
|
pycityagent/economy/__init__.py,sha256=aonY4WHnx-6EGJ4WKrx4S-2jAkYNLtqUA04jp6q8B7w,75
|
4
4
|
pycityagent/economy/econ_client.py,sha256=qQb_kZneEXGBRaS_y5Jdoi95I8GyjKEsDSC4s6V6R7w,10829
|
5
5
|
pycityagent/environment/__init__.py,sha256=awHxlOud-btWbk0FCS4RmGJ13W84oVCkbGfcrhKqihA,240
|
@@ -21,7 +21,7 @@ pycityagent/environment/sim/person_service.py,sha256=nIvOsoBoqOTDYtsiThg07-4ZBgk
|
|
21
21
|
pycityagent/environment/sim/road_service.py,sha256=phKTwTyhc_6Ht2mddEXpdENfl-lRXIVY0CHAlw1yHjI,1264
|
22
22
|
pycityagent/environment/sim/sim_env.py,sha256=HI1LcS_FotDKQ6vBnx0e49prXSABOfA20aU9KM-ZkCY,4625
|
23
23
|
pycityagent/environment/sim/social_service.py,sha256=6Iqvq6dz8H2jhLLdtaITc6Js9QnQw-Ylsd5AZgUj3-E,1993
|
24
|
-
pycityagent/environment/simulator.py,sha256=
|
24
|
+
pycityagent/environment/simulator.py,sha256=tLYiWsnFJhAbJsqCseFpmamfG4zHszg1dYu9BUvyGUQ,11913
|
25
25
|
pycityagent/environment/utils/__init__.py,sha256=1m4Q1EfGvNpUsa1bgQzzCyWhfkpElnskNImjjFD3Znc,237
|
26
26
|
pycityagent/environment/utils/base64.py,sha256=hoREzQo3FXMN79pqQLO2jgsDEvudciomyKii7MWljAM,374
|
27
27
|
pycityagent/environment/utils/const.py,sha256=3RMNy7_bE7-23K90j9DFW_tWEzu8s7hSTgKbV-3BFl4,5327
|
@@ -32,23 +32,23 @@ pycityagent/environment/utils/port.py,sha256=3OM6kSUt3PxvDUOlgyiendBtETaWU8Mzk_8
|
|
32
32
|
pycityagent/environment/utils/protobuf.py,sha256=0jBvK_s96y_n7tuMbG22TOtQmg71SGV4ONDy2IGsU9o,1148
|
33
33
|
pycityagent/llm/__init__.py,sha256=7klKEmCcDWJIu-F4DoAukSuKfDbLhdczrSIhpwow-sY,145
|
34
34
|
pycityagent/llm/embedding.py,sha256=Y0xhm_Ny6cawqzlendXb-mAS2QAuuEez1UtTR5-Kb2Q,4293
|
35
|
-
pycityagent/llm/llm.py,sha256=
|
35
|
+
pycityagent/llm/llm.py,sha256=BtxBvPK4tb8QlZIfxO5XJ73lKXwF8L31LqVbejWB8eo,15121
|
36
36
|
pycityagent/llm/llmconfig.py,sha256=4Ylf4OFSBEFy8jrOneeX0HvPhWEaF5jGvy1HkXK08Ro,436
|
37
37
|
pycityagent/llm/utils.py,sha256=hoNPhvomb1u6lhFX0GctFipw74hVKb7bvUBDqwBzBYw,160
|
38
38
|
pycityagent/memory/__init__.py,sha256=Hs2NhYpIG-lvpwPWwj4DydB1sxtjz7cuA4iDAzCXnjI,243
|
39
39
|
pycityagent/memory/const.py,sha256=m9AidLs7Zu28StpvYetclqx-1qQcy3bYvwagcXB3a04,913
|
40
40
|
pycityagent/memory/memory.py,sha256=sDbaqr1Koqf_9joMtG9PmmVxJZ6Rq7nAZO6EO0OdVgo,18148
|
41
|
-
pycityagent/memory/memory_base.py,sha256=
|
42
|
-
pycityagent/memory/profile.py,sha256=
|
43
|
-
pycityagent/memory/self_define.py,sha256=
|
44
|
-
pycityagent/memory/state.py,sha256=
|
45
|
-
pycityagent/memory/utils.py,sha256=
|
41
|
+
pycityagent/memory/memory_base.py,sha256=bd2q0qNu5hCRd2u4cPxE3bBA2OaoAD1oR4-vbRdbd_s,5594
|
42
|
+
pycityagent/memory/profile.py,sha256=s4LnxSPGSjIGZXHXkkd8mMa6uYYZrytgyQdWjcaqGf4,5182
|
43
|
+
pycityagent/memory/self_define.py,sha256=poPiexNhOLq_iTgK8s4mK_xoL_DAAcB8kMvInj7iE5E,5179
|
44
|
+
pycityagent/memory/state.py,sha256=5W0c1yJ-aaPpE74B2LEcw3Ygpm77tyooHv8NylyrozE,5113
|
45
|
+
pycityagent/memory/utils.py,sha256=wLNlNlZ-AY9VB8kbUIy0UQSYh26FOQABbhmKQkit5o8,850
|
46
46
|
pycityagent/message/__init__.py,sha256=TCjazxqb5DVwbTu1fF0sNvaH_EPXVuj2XQ0p6W-QCLU,55
|
47
|
-
pycityagent/message/messager.py,sha256=
|
47
|
+
pycityagent/message/messager.py,sha256=kLwh4SarqDc73hlmE7rhw3qwpeB7YMpSOGl0z7WAELE,2606
|
48
48
|
pycityagent/simulation/__init__.py,sha256=jYaqaNpzM5M_e_ykISS_M-mIyYdzJXJWhgpfBpA6l5k,111
|
49
|
-
pycityagent/simulation/agentgroup.py,sha256=
|
49
|
+
pycityagent/simulation/agentgroup.py,sha256=Wst0sCdXuwCWEFWDSsW3Eh-VacMiFfSWmfaV_fc17Lk,5423
|
50
50
|
pycityagent/simulation/interview.py,sha256=S2uv8MFCB4-u_4Q202VFoPJOIleqpKK9Piju0BDSb_0,1158
|
51
|
-
pycityagent/simulation/simulation.py,sha256=
|
51
|
+
pycityagent/simulation/simulation.py,sha256=cKeCjRYAjJMwuy6apjGZ8pEfPLJZiKSiphS7zb5Xojs,16955
|
52
52
|
pycityagent/simulation/survey/__init__.py,sha256=rxwou8U9KeFSP7rMzXtmtp2fVFZxK4Trzi-psx9LPIs,153
|
53
53
|
pycityagent/simulation/survey/manager.py,sha256=Tqini-4-uBZDsChVVL4ezlgXatnrxAfvceAZZRP8E48,2062
|
54
54
|
pycityagent/simulation/survey/models.py,sha256=sY4OrrG1h9iBnjBsyDage4T3mUFPBHHZQe-ORtwSjKc,1305
|
@@ -65,6 +65,6 @@ pycityagent/workflow/block.py,sha256=6EmiRMLdOZC1wMlmLMIjfrp9TuiI7Gw4s3nnXVMbrnw
|
|
65
65
|
pycityagent/workflow/prompt.py,sha256=tY69nDO8fgYfF_dOA-iceR8pAhkYmCqoox8uRPqEuGY,2956
|
66
66
|
pycityagent/workflow/tool.py,sha256=wD9WZ5rma6HCKugtHTwbShNE0f-Rjlwvn_1be3fCAsk,6682
|
67
67
|
pycityagent/workflow/trigger.py,sha256=t5X_i0WtL32bipZSsq_E3UUyYYudYLxQUpvxbgClp2s,5683
|
68
|
-
pycityagent-2.0.
|
69
|
-
pycityagent-2.0.
|
70
|
-
pycityagent-2.0.
|
68
|
+
pycityagent-2.0.0a11.dist-info/METADATA,sha256=ffwBhwzpEP59azqdbLj5k_uY11S_Qn2gdved0WMrksU,7622
|
69
|
+
pycityagent-2.0.0a11.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
|
70
|
+
pycityagent-2.0.0a11.dist-info/RECORD,,
|
File without changes
|