pycityagent 2.0.0a52__cp312-cp312-macosx_11_0_arm64.whl → 2.0.0a54__cp312-cp312-macosx_11_0_arm64.whl
Sign up to get free protection for your applications and to get access to all the features.
- pycityagent/agent/agent.py +83 -62
- pycityagent/agent/agent_base.py +81 -54
- pycityagent/cityagent/bankagent.py +5 -7
- pycityagent/cityagent/blocks/__init__.py +0 -2
- pycityagent/cityagent/blocks/cognition_block.py +149 -172
- pycityagent/cityagent/blocks/economy_block.py +90 -129
- pycityagent/cityagent/blocks/mobility_block.py +56 -29
- pycityagent/cityagent/blocks/needs_block.py +163 -145
- pycityagent/cityagent/blocks/other_block.py +17 -9
- pycityagent/cityagent/blocks/plan_block.py +45 -57
- pycityagent/cityagent/blocks/social_block.py +70 -51
- pycityagent/cityagent/blocks/utils.py +2 -0
- pycityagent/cityagent/firmagent.py +6 -7
- pycityagent/cityagent/governmentagent.py +7 -9
- pycityagent/cityagent/memory_config.py +48 -48
- pycityagent/cityagent/message_intercept.py +99 -0
- pycityagent/cityagent/nbsagent.py +6 -29
- pycityagent/cityagent/societyagent.py +325 -127
- pycityagent/cli/wrapper.py +4 -0
- pycityagent/economy/econ_client.py +0 -2
- pycityagent/environment/__init__.py +7 -1
- pycityagent/environment/sim/client.py +10 -1
- pycityagent/environment/sim/clock_service.py +2 -2
- pycityagent/environment/sim/pause_service.py +61 -0
- pycityagent/environment/sim/sim_env.py +34 -46
- pycityagent/environment/simulator.py +18 -14
- pycityagent/llm/embeddings.py +0 -24
- pycityagent/llm/llm.py +18 -10
- pycityagent/memory/faiss_query.py +29 -26
- pycityagent/memory/memory.py +733 -247
- pycityagent/message/__init__.py +8 -1
- pycityagent/message/message_interceptor.py +322 -0
- pycityagent/message/messager.py +42 -11
- pycityagent/pycityagent-sim +0 -0
- pycityagent/simulation/agentgroup.py +137 -96
- pycityagent/simulation/simulation.py +184 -38
- pycityagent/simulation/storage/pg.py +2 -2
- pycityagent/tools/tool.py +7 -9
- pycityagent/utils/__init__.py +7 -2
- pycityagent/utils/pg_query.py +1 -0
- pycityagent/utils/survey_util.py +26 -23
- pycityagent/workflow/block.py +14 -7
- {pycityagent-2.0.0a52.dist-info → pycityagent-2.0.0a54.dist-info}/METADATA +2 -2
- {pycityagent-2.0.0a52.dist-info → pycityagent-2.0.0a54.dist-info}/RECORD +48 -46
- pycityagent/cityagent/blocks/time_block.py +0 -116
- {pycityagent-2.0.0a52.dist-info → pycityagent-2.0.0a54.dist-info}/LICENSE +0 -0
- {pycityagent-2.0.0a52.dist-info → pycityagent-2.0.0a54.dist-info}/WHEEL +0 -0
- {pycityagent-2.0.0a52.dist-info → pycityagent-2.0.0a54.dist-info}/entry_points.txt +0 -0
- {pycityagent-2.0.0a52.dist-info → pycityagent-2.0.0a54.dist-info}/top_level.txt +0 -0
pycityagent/agent/agent.py
CHANGED
@@ -13,7 +13,7 @@ from ..economy import EconomyClient
|
|
13
13
|
from ..environment import Simulator
|
14
14
|
from ..llm import LLM
|
15
15
|
from ..memory import Memory
|
16
|
-
from ..message
|
16
|
+
from ..message import MessageInterceptor, Messager
|
17
17
|
from ..metrics import MlflowClient
|
18
18
|
from .agent_base import Agent, AgentType
|
19
19
|
|
@@ -30,10 +30,10 @@ class CitizenAgent(Agent):
|
|
30
30
|
name: str,
|
31
31
|
llm_client: Optional[LLM] = None,
|
32
32
|
simulator: Optional[Simulator] = None,
|
33
|
-
mlflow_client: Optional[MlflowClient] = None,
|
34
33
|
memory: Optional[Memory] = None,
|
35
34
|
economy_client: Optional[EconomyClient] = None,
|
36
35
|
messager: Optional[Messager] = None, # type:ignore
|
36
|
+
message_interceptor: Optional[MessageInterceptor] = None, # type:ignore
|
37
37
|
avro_file: Optional[dict] = None,
|
38
38
|
) -> None:
|
39
39
|
super().__init__(
|
@@ -42,11 +42,12 @@ class CitizenAgent(Agent):
|
|
42
42
|
llm_client=llm_client,
|
43
43
|
economy_client=economy_client,
|
44
44
|
messager=messager,
|
45
|
+
message_interceptor=message_interceptor,
|
45
46
|
simulator=simulator,
|
46
|
-
mlflow_client=mlflow_client,
|
47
47
|
memory=memory,
|
48
48
|
avro_file=avro_file,
|
49
49
|
)
|
50
|
+
self._mlflow_client = None
|
50
51
|
|
51
52
|
async def bind_to_simulator(self):
|
52
53
|
await self._bind_to_simulator()
|
@@ -62,42 +63,31 @@ class CitizenAgent(Agent):
|
|
62
63
|
if self._simulator is None:
|
63
64
|
logger.warning("Simulator is not set")
|
64
65
|
return
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
continue
|
91
|
-
resp = await simulator.add_person(
|
92
|
-
dict2pb(dict_person, person_pb2.Person())
|
93
|
-
)
|
94
|
-
person_id = resp["person_id"]
|
95
|
-
await memory.update("id", person_id, protect_llm_read_only_fields=False)
|
96
|
-
logger.debug(f"Binding to Person `{person_id}` just added to Simulator")
|
97
|
-
# 防止模拟器还没有到prepare阶段导致get_person出错
|
98
|
-
self._has_bound_to_simulator = True
|
99
|
-
self._agent_id = person_id
|
100
|
-
self.memory.set_agent_id(person_id)
|
66
|
+
FROM_MEMORY_KEYS = {
|
67
|
+
"attribute",
|
68
|
+
"home",
|
69
|
+
"work",
|
70
|
+
"vehicle_attribute",
|
71
|
+
"bus_attribute",
|
72
|
+
"pedestrian_attribute",
|
73
|
+
"bike_attribute",
|
74
|
+
}
|
75
|
+
simulator = self.simulator
|
76
|
+
status = self.status
|
77
|
+
dict_person = deepcopy(self._person_template)
|
78
|
+
for _key in FROM_MEMORY_KEYS:
|
79
|
+
try:
|
80
|
+
_value = await status.get(_key)
|
81
|
+
if _value:
|
82
|
+
dict_person[_key] = _value
|
83
|
+
except KeyError as e:
|
84
|
+
continue
|
85
|
+
resp = await simulator.add_person(dict2pb(dict_person, person_pb2.Person()))
|
86
|
+
person_id = resp["person_id"]
|
87
|
+
await status.update("id", person_id, protect_llm_read_only_fields=False)
|
88
|
+
logger.debug(f"Binding to Person `{person_id}` just added to Simulator")
|
89
|
+
self._agent_id = person_id
|
90
|
+
self.status.set_agent_id(person_id)
|
101
91
|
|
102
92
|
async def _bind_to_economy(self):
|
103
93
|
if self._economy_client is None:
|
@@ -109,8 +99,8 @@ class CitizenAgent(Agent):
|
|
109
99
|
await self._economy_client.remove_agents([self._agent_id])
|
110
100
|
except:
|
111
101
|
pass
|
112
|
-
person_id = await self.
|
113
|
-
currency = await self.
|
102
|
+
person_id = await self.status.get("id")
|
103
|
+
currency = await self.status.get("currency")
|
114
104
|
await self._economy_client.add_agents(
|
115
105
|
{
|
116
106
|
"id": person_id,
|
@@ -128,17 +118,32 @@ class CitizenAgent(Agent):
|
|
128
118
|
# 从消息中解析发送者 ID 和消息内容
|
129
119
|
target = payload["target"]
|
130
120
|
sender_id = payload["from"]
|
131
|
-
content = await self.
|
121
|
+
content = await self.status.get(f"{target}")
|
132
122
|
payload = {
|
133
123
|
"from": self._uuid,
|
134
124
|
"content": content,
|
135
125
|
}
|
136
126
|
await self._send_message(sender_id, payload, "gather")
|
137
127
|
|
128
|
+
@property
|
129
|
+
def mlflow_client(self) -> MlflowClient:
|
130
|
+
"""The Agent's MlflowClient"""
|
131
|
+
if self._mlflow_client is None:
|
132
|
+
raise RuntimeError(
|
133
|
+
f"MlflowClient access before assignment, please `set_mlflow_client` first!"
|
134
|
+
)
|
135
|
+
return self._mlflow_client
|
136
|
+
|
137
|
+
def set_mlflow_client(self, mlflow_client: MlflowClient):
|
138
|
+
"""
|
139
|
+
Set the mlflow_client of the agent.
|
140
|
+
"""
|
141
|
+
self._mlflow_client = mlflow_client
|
142
|
+
|
138
143
|
|
139
144
|
class InstitutionAgent(Agent):
|
140
145
|
"""
|
141
|
-
InstitutionAgent:
|
146
|
+
InstitutionAgent: Institution agent class and definition
|
142
147
|
"""
|
143
148
|
|
144
149
|
def __init__(
|
@@ -146,10 +151,10 @@ class InstitutionAgent(Agent):
|
|
146
151
|
name: str,
|
147
152
|
llm_client: Optional[LLM] = None,
|
148
153
|
simulator: Optional[Simulator] = None,
|
149
|
-
mlflow_client: Optional[MlflowClient] = None,
|
150
154
|
memory: Optional[Memory] = None,
|
151
155
|
economy_client: Optional[EconomyClient] = None,
|
152
156
|
messager: Optional[Messager] = None, # type:ignore
|
157
|
+
message_interceptor: Optional[MessageInterceptor] = None, # type:ignore
|
153
158
|
avro_file: Optional[dict] = None,
|
154
159
|
) -> None:
|
155
160
|
super().__init__(
|
@@ -157,12 +162,13 @@ class InstitutionAgent(Agent):
|
|
157
162
|
type=AgentType.Institution,
|
158
163
|
llm_client=llm_client,
|
159
164
|
economy_client=economy_client,
|
160
|
-
mlflow_client=mlflow_client,
|
161
165
|
messager=messager,
|
166
|
+
message_interceptor=message_interceptor,
|
162
167
|
simulator=simulator,
|
163
168
|
memory=memory,
|
164
169
|
avro_file=avro_file,
|
165
170
|
)
|
171
|
+
self._mlflow_client = None
|
166
172
|
# 添加响应收集器
|
167
173
|
self._gather_responses: dict[str, asyncio.Future] = {}
|
168
174
|
|
@@ -178,10 +184,10 @@ class InstitutionAgent(Agent):
|
|
178
184
|
# TODO: More general id generation
|
179
185
|
_id = random.randint(100000, 999999)
|
180
186
|
self._agent_id = _id
|
181
|
-
self.
|
187
|
+
self.status.set_agent_id(_id)
|
182
188
|
map_header = self.simulator.map.header
|
183
189
|
# TODO: remove random position assignment
|
184
|
-
await self.
|
190
|
+
await self.status.update(
|
185
191
|
"position",
|
186
192
|
{
|
187
193
|
"xy_position": {
|
@@ -201,57 +207,57 @@ class InstitutionAgent(Agent):
|
|
201
207
|
},
|
202
208
|
protect_llm_read_only_fields=False,
|
203
209
|
)
|
204
|
-
await self.
|
210
|
+
await self.status.update("id", _id, protect_llm_read_only_fields=False)
|
205
211
|
try:
|
206
212
|
await self._economy_client.remove_orgs([self._agent_id])
|
207
213
|
except:
|
208
214
|
pass
|
209
215
|
try:
|
210
|
-
|
211
|
-
_id = await
|
212
|
-
_type = await
|
216
|
+
_status = self.status
|
217
|
+
_id = await _status.get("id")
|
218
|
+
_type = await _status.get("type")
|
213
219
|
try:
|
214
|
-
nominal_gdp = await
|
220
|
+
nominal_gdp = await _status.get("nominal_gdp")
|
215
221
|
except:
|
216
222
|
nominal_gdp = []
|
217
223
|
try:
|
218
|
-
real_gdp = await
|
224
|
+
real_gdp = await _status.get("real_gdp")
|
219
225
|
except:
|
220
226
|
real_gdp = []
|
221
227
|
try:
|
222
|
-
unemployment = await
|
228
|
+
unemployment = await _status.get("unemployment")
|
223
229
|
except:
|
224
230
|
unemployment = []
|
225
231
|
try:
|
226
|
-
wages = await
|
232
|
+
wages = await _status.get("wages")
|
227
233
|
except:
|
228
234
|
wages = []
|
229
235
|
try:
|
230
|
-
prices = await
|
236
|
+
prices = await _status.get("prices")
|
231
237
|
except:
|
232
238
|
prices = []
|
233
239
|
try:
|
234
|
-
inventory = await
|
240
|
+
inventory = await _status.get("inventory")
|
235
241
|
except:
|
236
242
|
inventory = 0
|
237
243
|
try:
|
238
|
-
price = await
|
244
|
+
price = await _status.get("price")
|
239
245
|
except:
|
240
246
|
price = 0
|
241
247
|
try:
|
242
|
-
currency = await
|
248
|
+
currency = await _status.get("currency")
|
243
249
|
except:
|
244
250
|
currency = 0.0
|
245
251
|
try:
|
246
|
-
interest_rate = await
|
252
|
+
interest_rate = await _status.get("interest_rate")
|
247
253
|
except:
|
248
254
|
interest_rate = 0.0
|
249
255
|
try:
|
250
|
-
bracket_cutoffs = await
|
256
|
+
bracket_cutoffs = await _status.get("bracket_cutoffs")
|
251
257
|
except:
|
252
258
|
bracket_cutoffs = []
|
253
259
|
try:
|
254
|
-
bracket_rates = await
|
260
|
+
bracket_rates = await _status.get("bracket_rates")
|
255
261
|
except:
|
256
262
|
bracket_rates = []
|
257
263
|
await self._economy_client.add_orgs(
|
@@ -322,3 +328,18 @@ class InstitutionAgent(Agent):
|
|
322
328
|
# 清理Future
|
323
329
|
for key in futures:
|
324
330
|
self._gather_responses.pop(key, None)
|
331
|
+
|
332
|
+
@property
|
333
|
+
def mlflow_client(self) -> MlflowClient:
|
334
|
+
"""The Agent's MlflowClient"""
|
335
|
+
if self._mlflow_client is None:
|
336
|
+
raise RuntimeError(
|
337
|
+
f"MlflowClient access before assignment, please `set_mlflow_client` first!"
|
338
|
+
)
|
339
|
+
return self._mlflow_client
|
340
|
+
|
341
|
+
def set_mlflow_client(self, mlflow_client: MlflowClient):
|
342
|
+
"""
|
343
|
+
Set the mlflow_client of the agent.
|
344
|
+
"""
|
345
|
+
self._mlflow_client = mlflow_client
|
pycityagent/agent/agent_base.py
CHANGED
@@ -13,14 +13,13 @@ from typing import Any, Optional, Union, get_type_hints
|
|
13
13
|
import fastavro
|
14
14
|
import ray
|
15
15
|
from pycityproto.city.person.v2 import person_pb2 as person_pb2
|
16
|
-
from pyparsing import Dict
|
17
16
|
|
18
17
|
from ..economy import EconomyClient
|
19
18
|
from ..environment import Simulator
|
20
19
|
from ..environment.sim.person_service import PersonService
|
21
20
|
from ..llm import LLM
|
22
21
|
from ..memory import Memory
|
23
|
-
from ..message
|
22
|
+
from ..message import MessageInterceptor, Messager
|
24
23
|
from ..metrics import MlflowClient
|
25
24
|
from ..utils import DIALOG_SCHEMA, SURVEY_SCHEMA, process_survey_for_llm
|
26
25
|
from ..workflow import Block
|
@@ -48,6 +47,7 @@ class Agent(ABC):
|
|
48
47
|
|
49
48
|
configurable_fields: list[str] = []
|
50
49
|
default_values: dict[str, Any] = {}
|
50
|
+
fields_description: dict[str, str] = {}
|
51
51
|
|
52
52
|
def __init__(
|
53
53
|
self,
|
@@ -55,9 +55,9 @@ class Agent(ABC):
|
|
55
55
|
type: AgentType = AgentType.Unspecified,
|
56
56
|
llm_client: Optional[LLM] = None,
|
57
57
|
economy_client: Optional[EconomyClient] = None,
|
58
|
-
messager: Optional[
|
58
|
+
messager: Optional[ray.ObjectRef] = None,
|
59
|
+
message_interceptor: Optional[ray.ObjectRef] = None,
|
59
60
|
simulator: Optional[Simulator] = None,
|
60
|
-
mlflow_client: Optional[MlflowClient] = None,
|
61
61
|
memory: Optional[Memory] = None,
|
62
62
|
avro_file: Optional[dict[str, str]] = None,
|
63
63
|
copy_writer: Optional[ray.ObjectRef] = None,
|
@@ -72,7 +72,6 @@ class Agent(ABC):
|
|
72
72
|
economy_client (EconomyClient): The `EconomySim` client. Defaults to None.
|
73
73
|
messager (Messager, optional): The messager object. Defaults to None.
|
74
74
|
simulator (Simulator, optional): The simulator object. Defaults to None.
|
75
|
-
mlflow_client (MlflowClient, optional): The Mlflow object. Defaults to None.
|
76
75
|
memory (Memory, optional): The memory of the agent. Defaults to None.
|
77
76
|
avro_file (dict[str, str], optional): The avro file of the agent. Defaults to None.
|
78
77
|
copy_writer (ray.ObjectRef): The copy_writer of the agent. Defaults to None.
|
@@ -83,8 +82,8 @@ class Agent(ABC):
|
|
83
82
|
self._llm_client = llm_client
|
84
83
|
self._economy_client = economy_client
|
85
84
|
self._messager = messager
|
85
|
+
self._message_interceptor = message_interceptor
|
86
86
|
self._simulator = simulator
|
87
|
-
self._mlflow_client = mlflow_client
|
88
87
|
self._memory = memory
|
89
88
|
self._exp_id = -1
|
90
89
|
self._agent_id = -1
|
@@ -104,13 +103,22 @@ class Agent(ABC):
|
|
104
103
|
return state
|
105
104
|
|
106
105
|
@classmethod
|
107
|
-
def export_class_config(cls) -> dict[str,
|
108
|
-
result = {
|
106
|
+
def export_class_config(cls) -> dict[str, dict]:
|
107
|
+
result = {
|
108
|
+
"agent_name": cls.__name__,
|
109
|
+
"config": {},
|
110
|
+
"description": {},
|
111
|
+
"blocks": [],
|
112
|
+
}
|
109
113
|
config = {
|
110
114
|
field: cls.default_values.get(field, "default_value")
|
111
115
|
for field in cls.configurable_fields
|
112
116
|
}
|
113
117
|
result["config"] = config
|
118
|
+
result["description"] = {
|
119
|
+
field: cls.fields_description.get(field, "")
|
120
|
+
for field in cls.configurable_fields
|
121
|
+
}
|
114
122
|
# 解析类中的注解,找到Block类型的字段
|
115
123
|
hints = get_type_hints(cls)
|
116
124
|
for attr_name, attr_type in hints.items():
|
@@ -119,14 +127,15 @@ class Agent(ABC):
|
|
119
127
|
result["blocks"].append(
|
120
128
|
{
|
121
129
|
"name": attr_name,
|
122
|
-
"config": block_config,
|
130
|
+
"config": block_config[0], # type:ignore
|
131
|
+
"description": block_config[1], # type:ignore
|
123
132
|
"children": cls._export_subblocks(attr_type),
|
124
133
|
}
|
125
134
|
)
|
126
135
|
return result
|
127
136
|
|
128
137
|
@classmethod
|
129
|
-
def _export_subblocks(cls, block_cls: type[Block]) -> list[
|
138
|
+
def _export_subblocks(cls, block_cls: type[Block]) -> list[dict]:
|
130
139
|
children = []
|
131
140
|
hints = get_type_hints(block_cls) # 获取类的注解
|
132
141
|
for attr_name, attr_type in hints.items():
|
@@ -135,7 +144,8 @@ class Agent(ABC):
|
|
135
144
|
children.append(
|
136
145
|
{
|
137
146
|
"name": attr_name,
|
138
|
-
"config": block_config,
|
147
|
+
"config": block_config[0], # type:ignore
|
148
|
+
"description": block_config[1], # type:ignore
|
139
149
|
"children": cls._export_subblocks(attr_type),
|
140
150
|
}
|
141
151
|
)
|
@@ -216,12 +226,6 @@ class Agent(ABC):
|
|
216
226
|
"""
|
217
227
|
self._simulator = simulator
|
218
228
|
|
219
|
-
def set_mlflow_client(self, mlflow_client: MlflowClient):
|
220
|
-
"""
|
221
|
-
Set the mlflow_client of the agent.
|
222
|
-
"""
|
223
|
-
self._mlflow_client = mlflow_client
|
224
|
-
|
225
229
|
def set_economy_client(self, economy_client: EconomyClient):
|
226
230
|
"""
|
227
231
|
Set the economy_client of the agent.
|
@@ -252,6 +256,12 @@ class Agent(ABC):
|
|
252
256
|
"""
|
253
257
|
self._pgsql_writer = pgsql_writer
|
254
258
|
|
259
|
+
def set_message_interceptor(self, message_interceptor: ray.ObjectRef):
|
260
|
+
"""
|
261
|
+
Set the PostgreSQL copy writer of the agent.
|
262
|
+
"""
|
263
|
+
self._message_interceptor = message_interceptor
|
264
|
+
|
255
265
|
@property
|
256
266
|
def uuid(self):
|
257
267
|
"""The Agent's UUID"""
|
@@ -279,16 +289,7 @@ class Agent(ABC):
|
|
279
289
|
f"EconomyClient access before assignment, please `set_economy_client` first!"
|
280
290
|
)
|
281
291
|
return self._economy_client
|
282
|
-
|
283
|
-
@property
|
284
|
-
def mlflow_client(self):
|
285
|
-
"""The Agent's MlflowClient"""
|
286
|
-
if self._mlflow_client is None:
|
287
|
-
raise RuntimeError(
|
288
|
-
f"MlflowClient access before assignment, please `set_mlflow_client` first!"
|
289
|
-
)
|
290
|
-
return self._mlflow_client
|
291
|
-
|
292
|
+
|
292
293
|
@property
|
293
294
|
def memory(self):
|
294
295
|
"""The Agent's Memory"""
|
@@ -298,6 +299,24 @@ class Agent(ABC):
|
|
298
299
|
)
|
299
300
|
return self._memory
|
300
301
|
|
302
|
+
@property
|
303
|
+
def status(self):
|
304
|
+
"""The Agent's Status Memory"""
|
305
|
+
if self.memory.status is None:
|
306
|
+
raise RuntimeError(
|
307
|
+
f"Status access before assignment, please `set_memory` first!"
|
308
|
+
)
|
309
|
+
return self.memory.status
|
310
|
+
|
311
|
+
@property
|
312
|
+
def stream(self):
|
313
|
+
"""The Agent's Stream Memory"""
|
314
|
+
if self.memory.stream is None:
|
315
|
+
raise RuntimeError(
|
316
|
+
f"Stream access before assignment, please `set_memory` first!"
|
317
|
+
)
|
318
|
+
return self.memory.stream
|
319
|
+
|
301
320
|
@property
|
302
321
|
def simulator(self):
|
303
322
|
"""The Simulator"""
|
@@ -315,11 +334,17 @@ class Agent(ABC):
|
|
315
334
|
f"Copy Writer access before assignment, please `set_pgsql_writer` first!"
|
316
335
|
)
|
317
336
|
return self._pgsql_writer
|
337
|
+
|
338
|
+
@property
|
339
|
+
def messager(self):
|
340
|
+
if self._messager is None:
|
341
|
+
raise RuntimeError("Messager is not set")
|
342
|
+
return self._messager
|
318
343
|
|
319
344
|
async def messager_ping(self):
|
320
345
|
if self._messager is None:
|
321
346
|
raise RuntimeError("Messager is not set")
|
322
|
-
return await self._messager.ping()
|
347
|
+
return await self._messager.ping.remote() # type:ignore
|
323
348
|
|
324
349
|
async def generate_user_survey_response(self, survey: dict) -> str:
|
325
350
|
"""生成回答 —— 可重写
|
@@ -338,22 +363,15 @@ class Agent(ABC):
|
|
338
363
|
|
339
364
|
# 添加记忆上下文
|
340
365
|
if self._memory:
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
if relevant_memories:
|
351
|
-
dialog.append(
|
352
|
-
{
|
353
|
-
"role": "system",
|
354
|
-
"content": f"Answer based on these memories:\n{relevant_memories}",
|
355
|
-
}
|
356
|
-
)
|
366
|
+
profile_and_states = await self.status.search(survey_prompt)
|
367
|
+
relevant_activities = await self.stream.search(survey_prompt)
|
368
|
+
|
369
|
+
dialog.append(
|
370
|
+
{
|
371
|
+
"role": "system",
|
372
|
+
"content": f"Answer based on following profile and states:\n{profile_and_states}\n Related activities:\n{relevant_activities}",
|
373
|
+
}
|
374
|
+
)
|
357
375
|
|
358
376
|
# 添加问卷问题
|
359
377
|
dialog.append({"role": "user", "content": survey_prompt})
|
@@ -412,6 +430,7 @@ class Agent(ABC):
|
|
412
430
|
_data_tuples
|
413
431
|
)
|
414
432
|
)
|
433
|
+
await self.messager.send_message.remote(f"exps/{self._exp_id}/user_payback", {"count": 1})# type:ignore
|
415
434
|
|
416
435
|
async def generate_user_chat_response(self, question: str) -> str:
|
417
436
|
"""生成回答 —— 可重写
|
@@ -430,14 +449,15 @@ class Agent(ABC):
|
|
430
449
|
|
431
450
|
# 添加记忆上下文
|
432
451
|
if self._memory:
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
}
|
440
|
-
|
452
|
+
profile_and_states = await self.status.search(question, top_k=10)
|
453
|
+
relevant_activities = await self.stream.search(question, top_k=10)
|
454
|
+
|
455
|
+
dialog.append(
|
456
|
+
{
|
457
|
+
"role": "system",
|
458
|
+
"content": f"Answer based on following profile and states:\n{profile_and_states}\n Related activities:\n{relevant_activities}",
|
459
|
+
}
|
460
|
+
)
|
441
461
|
|
442
462
|
# 添加用户问题
|
443
463
|
dialog.append({"role": "user", "content": question})
|
@@ -497,6 +517,8 @@ class Agent(ABC):
|
|
497
517
|
_data
|
498
518
|
)
|
499
519
|
)
|
520
|
+
await self.messager.send_message.remote(f"exps/{self._exp_id}/user_payback", {"count": 1})# type:ignore
|
521
|
+
print(f"Sent payback message to {self._exp_id}")
|
500
522
|
|
501
523
|
async def process_agent_chat_response(self, payload: dict) -> str:
|
502
524
|
resp = f"Agent {self._uuid} received agent chat response: {payload}"
|
@@ -566,7 +588,12 @@ class Agent(ABC):
|
|
566
588
|
if self._messager is None:
|
567
589
|
raise RuntimeError("Messager is not set")
|
568
590
|
topic = f"exps/{self._exp_id}/agents/{to_agent_uuid}/{sub_topic}"
|
569
|
-
await self._messager.send_message.remote(
|
591
|
+
await self._messager.send_message.remote( # type:ignore
|
592
|
+
topic,
|
593
|
+
payload,
|
594
|
+
self._uuid,
|
595
|
+
to_agent_uuid,
|
596
|
+
)
|
570
597
|
|
571
598
|
async def send_message_to_agent(
|
572
599
|
self, to_agent_uuid: str, content: str, type: str = "social"
|
@@ -630,6 +657,6 @@ class Agent(ABC):
|
|
630
657
|
当_blocked为True时,不执行forward方法
|
631
658
|
"""
|
632
659
|
if self._messager is not None:
|
633
|
-
await self._messager.ping.remote()
|
660
|
+
await self._messager.ping.remote() # type:ignore
|
634
661
|
if not self._blocked:
|
635
662
|
await self.forward()
|
@@ -53,14 +53,12 @@ class BankAgent(InstitutionAgent):
|
|
53
53
|
|
54
54
|
async def forward(self):
|
55
55
|
if await self.month_trigger():
|
56
|
-
citizens = await self.memory.get("citizens")
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
break
|
61
|
-
await asyncio.sleep(1)
|
56
|
+
citizens = await self.memory.status.get("citizens")
|
57
|
+
agents_forward = []
|
58
|
+
if not np.all(np.array(agents_forward) > self.forward_times):
|
59
|
+
return
|
62
60
|
self.forward_times += 1
|
63
61
|
for uuid in citizens:
|
64
62
|
await self.send_message_to_agent(
|
65
|
-
uuid, f"bank_forward@{self.forward_times}"
|
63
|
+
uuid, f"bank_forward@{self.forward_times}", "economy"
|
66
64
|
)
|
@@ -5,7 +5,6 @@ from .needs_block import NeedsBlock
|
|
5
5
|
from .social_block import SocialBlock
|
6
6
|
from .economy_block import EconomyBlock
|
7
7
|
from .other_block import OtherBlock
|
8
|
-
from .time_block import TimeBlock
|
9
8
|
|
10
9
|
__all__ = [
|
11
10
|
"MobilityBlock",
|
@@ -16,5 +15,4 @@ __all__ = [
|
|
16
15
|
"EconomyBlock",
|
17
16
|
"OtherBlock",
|
18
17
|
"LongTermDecisionBlock",
|
19
|
-
"TimeBlock",
|
20
18
|
]
|