pycityagent 2.0.0a51__cp311-cp311-macosx_11_0_arm64.whl → 2.0.0a53__cp311-cp311-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 +48 -62
- pycityagent/agent/agent_base.py +66 -53
- 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 +44 -56
- 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/nbsagent.py +6 -29
- pycityagent/cityagent/societyagent.py +204 -119
- 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/simulator.py +17 -12
- pycityagent/llm/embeddings.py +0 -24
- pycityagent/memory/faiss_query.py +29 -26
- pycityagent/memory/memory.py +720 -272
- pycityagent/pycityagent-sim +0 -0
- pycityagent/simulation/agentgroup.py +92 -99
- pycityagent/simulation/simulation.py +115 -40
- pycityagent/tools/tool.py +7 -10
- pycityagent/workflow/block.py +11 -4
- {pycityagent-2.0.0a51.dist-info → pycityagent-2.0.0a53.dist-info}/METADATA +2 -2
- {pycityagent-2.0.0a51.dist-info → pycityagent-2.0.0a53.dist-info}/RECORD +35 -35
- {pycityagent-2.0.0a51.dist-info → pycityagent-2.0.0a53.dist-info}/WHEEL +1 -1
- pycityagent/cityagent/blocks/time_block.py +0 -116
- {pycityagent-2.0.0a51.dist-info → pycityagent-2.0.0a53.dist-info}/LICENSE +0 -0
- {pycityagent-2.0.0a51.dist-info → pycityagent-2.0.0a53.dist-info}/entry_points.txt +0 -0
- {pycityagent-2.0.0a51.dist-info → pycityagent-2.0.0a53.dist-info}/top_level.txt +0 -0
@@ -1,4 +1,4 @@
|
|
1
|
-
from pycityagent.llm
|
1
|
+
from pycityagent.llm import LLM
|
2
2
|
from pycityagent.workflow.block import Block
|
3
3
|
from pycityagent.memory import Memory
|
4
4
|
from pycityagent.environment.simulator import Simulator
|
@@ -23,47 +23,60 @@ def extract_json(output_str):
|
|
23
23
|
return None
|
24
24
|
|
25
25
|
class CognitionBlock(Block):
|
26
|
+
configurable_fields = ["top_k"]
|
27
|
+
default_values = {"top_k": 20}
|
28
|
+
fields_description = {
|
29
|
+
"top_k": "Number of most relevant memories to return, defaults to 20"
|
30
|
+
}
|
31
|
+
|
26
32
|
def __init__(self, llm: LLM, memory: Memory, simulator: Simulator):
|
27
|
-
super().__init__("CognitionBlock", llm, memory, simulator)
|
28
|
-
self.
|
29
|
-
self.time_diff = 24*60*60 # 24小时
|
30
|
-
self.trigger_time = 0
|
31
|
-
self.token_consumption = 0
|
33
|
+
super().__init__("CognitionBlock", llm=llm, memory=memory, simulator=simulator)
|
34
|
+
self.top_k = 20
|
32
35
|
|
33
36
|
async def set_status(self, status):
|
34
37
|
for key in status:
|
35
|
-
await self.memory.update(key, status[key])
|
38
|
+
await self.memory.status.update(key, status[key])
|
36
39
|
return
|
37
40
|
|
38
|
-
async def
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
41
|
+
async def attitude_update(self):
|
42
|
+
"""Cognition - attitude update workflow"""
|
43
|
+
attitude = await self.memory.status.get("attitude")
|
44
|
+
prompt_data = {
|
45
|
+
"gender": await self.memory.status.get("gender"),
|
46
|
+
"age": await self.memory.status.get("age"),
|
47
|
+
"race": await self.memory.status.get("race"),
|
48
|
+
"religion": await self.memory.status.get("religion"),
|
49
|
+
"marital_status": await self.memory.status.get("marital_status"),
|
50
|
+
"residence": await self.memory.status.get("residence"),
|
51
|
+
"occupation": await self.memory.status.get("occupation"),
|
52
|
+
"education": await self.memory.status.get("education"),
|
53
|
+
"personality": await self.memory.status.get("personality"),
|
54
|
+
"consumption": await self.memory.status.get("consumption"),
|
55
|
+
"family_consumption": await self.memory.status.get("family_consumption"),
|
56
|
+
"income": await self.memory.status.get("income"),
|
57
|
+
"skill": await self.memory.status.get("skill"),
|
58
|
+
"thought": await self.memory.status.get("thought"),
|
59
|
+
"emotion_types": await self.memory.status.get("emotion_types")
|
60
|
+
}
|
61
|
+
for topic in attitude:
|
62
|
+
description_prompt = """
|
63
|
+
You are a {gender}, aged {age}, belonging to the {race} race and identifying as {religion}.
|
64
|
+
Your marital status is {marital_status}, and you currently reside in a {residence} area.
|
65
|
+
Your occupation is {occupation}, and your education level is {education}.
|
66
|
+
You are {personality}, with a consumption level of {consumption} and a family consumption level of {family_consumption}.
|
67
|
+
Your income is {income}, and you are skilled in {skill}.
|
68
|
+
My current emotion intensities are (0 meaning not at all, 10 meaning very much):
|
69
|
+
sadness: {sadness}, joy: {joy}, fear: {fear}, disgust: {disgust}, anger: {anger}, surprise: {surprise}.
|
70
|
+
You have the following thoughts: {thought}.
|
71
|
+
In the following 21 words, I have chosen {emotion_types} to represent your current status:
|
72
|
+
Joy, Distress, Resentment, Pity, Hope, Fear, Satisfaction, Relief, Disappointment, Pride, Admiration, Shame, Reproach, Liking, Disliking, Gratitude, Anger, Gratification, Remorse, Love, Hate.
|
73
|
+
"""
|
74
|
+
incident_str = await self.memory.stream.search_today(top_k=self.top_k)
|
75
|
+
if incident_str:
|
76
|
+
incident_prompt = "Today, these incidents happened:"
|
77
|
+
incident_prompt += incident_str
|
78
|
+
else:
|
79
|
+
incident_prompt = "No incidents happened today."
|
67
80
|
previous_attitude = str(attitude[topic]) # Convert to string
|
68
81
|
problem_prompt = (
|
69
82
|
f"You need to decide your attitude towards topic: {topic}, "
|
@@ -71,70 +84,39 @@ class CognitionBlock(Block):
|
|
71
84
|
"(0 meaning oppose, 10 meaning support). "
|
72
85
|
"Please return a new attitude rating (0-10, smaller meaning oppose, larger meaning support) in JSON format, and explain, e.g. {{\"attitude\": 5}}"
|
73
86
|
)
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
skill=await self.memory.get("skill"),
|
105
|
-
sadness=sadness,
|
106
|
-
joy=joy,
|
107
|
-
fear=fear,
|
108
|
-
disgust=disgust,
|
109
|
-
anger=anger,
|
110
|
-
surprise=surprise,
|
111
|
-
thought=await self.memory.get("thought"),
|
112
|
-
emotion_types=await self.memory.get("emotion_types")
|
113
|
-
)
|
114
|
-
evaluation = True
|
115
|
-
for retry in range(10):
|
116
|
-
try:
|
117
|
-
response = await self.llm.atext_request(question_prompt.to_dialog(), timeout=300)
|
118
|
-
response = json.loads(extract_json(response))
|
119
|
-
evaluation = False
|
120
|
-
break
|
121
|
-
except:
|
122
|
-
pass
|
123
|
-
if evaluation:
|
124
|
-
raise f"Request for attitude:{topic} update failed"
|
125
|
-
logger.info(f"""Cognition updated attitude:{topic}:
|
126
|
-
attitude: {response['attitude']}""")
|
127
|
-
attitude[topic] = response["attitude"]
|
128
|
-
await self.memory.update("attitude", attitude)
|
129
|
-
return
|
87
|
+
question_prompt = description_prompt + incident_prompt + problem_prompt
|
88
|
+
question_prompt = FormatPrompt(question_prompt)
|
89
|
+
emotion = await self.memory.status.get("emotion")
|
90
|
+
sadness = emotion["sadness"]
|
91
|
+
joy = emotion["joy"]
|
92
|
+
fear = emotion["fear"]
|
93
|
+
disgust = emotion["disgust"]
|
94
|
+
anger = emotion["anger"]
|
95
|
+
surprise = emotion["surprise"]
|
96
|
+
prompt_data["sadness"] = sadness
|
97
|
+
prompt_data["joy"] = joy
|
98
|
+
prompt_data["fear"] = fear
|
99
|
+
prompt_data["disgust"] = disgust
|
100
|
+
prompt_data["anger"] = anger
|
101
|
+
prompt_data["surprise"] = surprise
|
102
|
+
|
103
|
+
question_prompt.format(**prompt_data)
|
104
|
+
evaluation = True
|
105
|
+
for retry in range(10):
|
106
|
+
try:
|
107
|
+
response = await self.llm.atext_request(question_prompt.to_dialog(), timeout=300)
|
108
|
+
response = json.loads(extract_json(response))
|
109
|
+
evaluation = False
|
110
|
+
break
|
111
|
+
except:
|
112
|
+
pass
|
113
|
+
if evaluation:
|
114
|
+
raise f"Request for attitude:{topic} update failed"
|
115
|
+
attitude[topic] = response["attitude"]
|
116
|
+
await self.memory.status.update("attitude", attitude)
|
130
117
|
|
131
|
-
async def
|
132
|
-
|
133
|
-
if not whether_trigger:
|
134
|
-
return
|
135
|
-
self.trigger_time += 1
|
136
|
-
consumption_start = self.llm.prompt_tokens_used + self.llm.completion_tokens_used
|
137
|
-
|
118
|
+
async def thought_update(self):
|
119
|
+
"""Cognition - thought update workflow"""
|
138
120
|
description_prompt = """
|
139
121
|
You are a {gender}, aged {age}, belonging to the {race} race and identifying as {religion}.
|
140
122
|
Your marital status is {marital_status}, and you currently reside in a {residence} area.
|
@@ -147,21 +129,20 @@ class CognitionBlock(Block):
|
|
147
129
|
In the following 21 words, I have chosen {emotion_types} to represent your current status:
|
148
130
|
Joy, Distress, Resentment, Pity, Hope, Fear, Satisfaction, Relief, Disappointment, Pride, Admiration, Shame, Reproach, Liking, Disliking, Gratitude, Anger, Gratification, Remorse, Love, Hate.
|
149
131
|
"""
|
150
|
-
|
151
|
-
if
|
152
|
-
incident_prompt = "Today, these incidents happened
|
153
|
-
for incident in incident_list:
|
154
|
-
incident_prompt += incident
|
132
|
+
incident_str = await self.memory.stream.search_today(top_k=20)
|
133
|
+
if incident_str:
|
134
|
+
incident_prompt = "Today, these incidents happened:\n" + incident_str
|
155
135
|
else:
|
156
136
|
incident_prompt = "No incidents happened today."
|
157
137
|
question_prompt = """
|
158
|
-
Please
|
159
|
-
|
160
|
-
|
161
|
-
|
138
|
+
Please review what happened today and share your thoughts and feelings about it.
|
139
|
+
Consider your current emotional state and experiences, then:
|
140
|
+
1. Summarize your thoughts and reflections on today's events
|
141
|
+
2. Choose one word that best describes your current emotional state from: Joy, Distress, Resentment, Pity, Hope, Fear, Satisfaction, Relief, Disappointment, Pride, Admiration, Shame, Reproach, Liking, Disliking, Gratitude, Anger, Gratification, Remorse, Love, Hate.
|
142
|
+
Return in JSON format, e.g. {{"thought": "Currently nothing good or bad is happening, I think ...."}}"""
|
162
143
|
question_prompt = description_prompt + incident_prompt + question_prompt
|
163
144
|
question_prompt = FormatPrompt(question_prompt)
|
164
|
-
emotion = await self.memory.get("emotion")
|
145
|
+
emotion = await self.memory.status.get("emotion")
|
165
146
|
sadness = emotion["sadness"]
|
166
147
|
joy = emotion["joy"]
|
167
148
|
fear = emotion["fear"]
|
@@ -169,28 +150,28 @@ class CognitionBlock(Block):
|
|
169
150
|
anger = emotion["anger"]
|
170
151
|
surprise = emotion["surprise"]
|
171
152
|
question_prompt.format(
|
172
|
-
gender=await self.memory.get("gender"),
|
173
|
-
age=await self.memory.get("age"),
|
174
|
-
race=await self.memory.get("race"),
|
175
|
-
religion=await self.memory.get("religion"),
|
176
|
-
marital_status=await self.memory.get("marital_status"),
|
177
|
-
residence=await self.memory.get("residence"),
|
178
|
-
occupation=await self.memory.get("occupation"),
|
179
|
-
education=await self.memory.get("education"),
|
180
|
-
personality=await self.memory.get("personality"),
|
181
|
-
consumption=await self.memory.get("consumption"),
|
182
|
-
family_consumption=await self.memory.get("family_consumption"),
|
183
|
-
income=await self.memory.get("income"),
|
184
|
-
skill=await self.memory.get("skill"),
|
153
|
+
gender=await self.memory.status.get("gender"),
|
154
|
+
age=await self.memory.status.get("age"),
|
155
|
+
race=await self.memory.status.get("race"),
|
156
|
+
religion=await self.memory.status.get("religion"),
|
157
|
+
marital_status=await self.memory.status.get("marital_status"),
|
158
|
+
residence=await self.memory.status.get("residence"),
|
159
|
+
occupation=await self.memory.status.get("occupation"),
|
160
|
+
education=await self.memory.status.get("education"),
|
161
|
+
personality=await self.memory.status.get("personality"),
|
162
|
+
consumption=await self.memory.status.get("consumption"),
|
163
|
+
family_consumption=await self.memory.status.get("family_consumption"),
|
164
|
+
income=await self.memory.status.get("income"),
|
165
|
+
skill=await self.memory.status.get("skill"),
|
185
166
|
sadness=sadness,
|
186
167
|
joy=joy,
|
187
168
|
fear=fear,
|
188
169
|
disgust=disgust,
|
189
170
|
anger=anger,
|
190
171
|
surprise=surprise,
|
191
|
-
emotion=await self.memory.get("emotion"),
|
192
|
-
thought=await self.memory.get("thought"),
|
193
|
-
emotion_types=await self.memory.get("emotion_types")
|
172
|
+
emotion=await self.memory.status.get("emotion"),
|
173
|
+
thought=await self.memory.status.get("thought"),
|
174
|
+
emotion_types=await self.memory.status.get("emotion_types")
|
194
175
|
)
|
195
176
|
|
196
177
|
evaluation = True
|
@@ -204,30 +185,32 @@ class CognitionBlock(Block):
|
|
204
185
|
pass
|
205
186
|
if evaluation:
|
206
187
|
raise Exception("Request for cognition update failed")
|
207
|
-
logger.info(f"""Cognition updated emotion intensities:
|
208
|
-
sadness: {response['sadness']},
|
209
|
-
joy: {response['joy']},
|
210
|
-
fear: {response['fear']},
|
211
|
-
disgust: {response['disgust']},
|
212
|
-
anger: {response['anger']},
|
213
|
-
surprise: {response['surprise']}"
|
214
|
-
thought: {response['thought']}
|
215
|
-
emotion_types: {response['word']}""")
|
216
188
|
|
217
|
-
|
218
|
-
await self.memory.update("
|
219
|
-
await self.memory.
|
220
|
-
await self.memory.update("emotion_types", str(response["word"]))
|
221
|
-
|
222
|
-
consumption_end = self.llm.prompt_tokens_used + self.llm.completion_tokens_used
|
223
|
-
self.token_consumption += consumption_end - consumption_start
|
189
|
+
thought = str(response["thought"])
|
190
|
+
await self.memory.status.update("thought", thought)
|
191
|
+
await self.memory.stream.add_cognition(description=thought)
|
224
192
|
return
|
225
193
|
|
226
|
-
async def
|
194
|
+
async def end_of_day(self):
|
195
|
+
"""Cognition - end of day workflow"""
|
196
|
+
time = await self.simulator.get_simulator_second_from_start_of_day()
|
197
|
+
if time >= 86400 - 10 * 60:
|
198
|
+
return True
|
199
|
+
return False
|
200
|
+
|
201
|
+
async def forward(self):
|
202
|
+
"""Cognition workflow: Daily update"""
|
203
|
+
# cognition update: thought and attitude
|
204
|
+
if await self.end_of_day():
|
205
|
+
await self.thought_update()
|
206
|
+
await self.attitude_update()
|
207
|
+
|
208
|
+
async def emotion_update(self, incident):
|
209
|
+
"""Cognition - emotion update workflow"""
|
227
210
|
whether_trigger = await self.check_trigger()
|
228
211
|
if not whether_trigger:
|
229
212
|
return
|
230
|
-
|
213
|
+
print(f"Updating emotion for {incident}")
|
231
214
|
description_prompt = """
|
232
215
|
You are a {gender}, aged {age}, belonging to the {race} race and identifying as {religion}.
|
233
216
|
Your marital status is {marital_status}, and you currently reside in a {residence} area.
|
@@ -241,14 +224,14 @@ class CognitionBlock(Block):
|
|
241
224
|
Joy, Distress, Resentment, Pity, Hope, Fear, Satisfaction, Relief, Disappointment, Pride, Admiration, Shame, Reproach, Liking, Disliking, Gratitude, Anger, Gratification, Remorse, Love, Hate.
|
242
225
|
"""
|
243
226
|
|
244
|
-
incident_prompt = incident #waiting for incident port
|
227
|
+
incident_prompt = f"{incident}" #waiting for incident port
|
245
228
|
question_prompt = """
|
246
229
|
Please reconsider your emotion intensities:
|
247
230
|
sadness, joy, fear, disgust, anger, surprise (0 meaning not at all, 10 meaning very much).
|
248
|
-
Return in JSON format, e.g. {{"sadness": 5, "joy": 5, "fear": 5, "disgust": 5, "anger": 5, "surprise": 5}}"""
|
231
|
+
Return in JSON format, e.g. {{"sadness": 5, "joy": 5, "fear": 5, "disgust": 5, "anger": 5, "surprise": 5, "conclusion": "I feel ..."}}"""
|
249
232
|
question_prompt = description_prompt + incident_prompt + question_prompt
|
250
233
|
question_prompt = FormatPrompt(question_prompt)
|
251
|
-
emotion = await self.memory.get("emotion")
|
234
|
+
emotion = await self.memory.status.get("emotion")
|
252
235
|
sadness = emotion["sadness"]
|
253
236
|
joy = emotion["joy"]
|
254
237
|
fear = emotion["fear"]
|
@@ -256,28 +239,28 @@ class CognitionBlock(Block):
|
|
256
239
|
anger = emotion["anger"]
|
257
240
|
surprise = emotion["surprise"]
|
258
241
|
question_prompt.format(
|
259
|
-
gender=await self.memory.get("gender"),
|
260
|
-
age=await self.memory.get("age"),
|
261
|
-
race=await self.memory.get("race"),
|
262
|
-
religion=await self.memory.get("religion"),
|
263
|
-
marital_status=await self.memory.get("marital_status"),
|
264
|
-
residence=await self.memory.get("residence"),
|
265
|
-
occupation=await self.memory.get("occupation"),
|
266
|
-
education=await self.memory.get("education"),
|
267
|
-
personality=await self.memory.get("personality"),
|
268
|
-
consumption=await self.memory.get("consumption"),
|
269
|
-
family_consumption=await self.memory.get("family_consumption"),
|
270
|
-
income=await self.memory.get("income"),
|
271
|
-
skill=await self.memory.get("skill"),
|
242
|
+
gender=await self.memory.status.get("gender"),
|
243
|
+
age=await self.memory.status.get("age"),
|
244
|
+
race=await self.memory.status.get("race"),
|
245
|
+
religion=await self.memory.status.get("religion"),
|
246
|
+
marital_status=await self.memory.status.get("marital_status"),
|
247
|
+
residence=await self.memory.status.get("residence"),
|
248
|
+
occupation=await self.memory.status.get("occupation"),
|
249
|
+
education=await self.memory.status.get("education"),
|
250
|
+
personality=await self.memory.status.get("personality"),
|
251
|
+
consumption=await self.memory.status.get("consumption"),
|
252
|
+
family_consumption=await self.memory.status.get("family_consumption"),
|
253
|
+
income=await self.memory.status.get("income"),
|
254
|
+
skill=await self.memory.status.get("skill"),
|
272
255
|
sadness=sadness,
|
273
256
|
joy=joy,
|
274
257
|
fear=fear,
|
275
258
|
disgust=disgust,
|
276
259
|
anger=anger,
|
277
260
|
surprise=surprise,
|
278
|
-
emotion=await self.memory.get("emotion"),
|
279
|
-
thought=await self.memory.get("thought"),
|
280
|
-
emotion_types=await self.memory.get("emotion_types")
|
261
|
+
emotion=await self.memory.status.get("emotion"),
|
262
|
+
thought=await self.memory.status.get("thought"),
|
263
|
+
emotion_types=await self.memory.status.get("emotion_types")
|
281
264
|
)
|
282
265
|
|
283
266
|
evaluation = True
|
@@ -288,17 +271,11 @@ class CognitionBlock(Block):
|
|
288
271
|
evaluation = False
|
289
272
|
break
|
290
273
|
except Exception as e:
|
291
|
-
|
274
|
+
logger.warning(f"Request for cognition update failed: {e}")
|
292
275
|
pass
|
293
276
|
if evaluation:
|
294
277
|
raise Exception("Request for cognition update failed")
|
295
|
-
logger.info(f"""Cognition updated emotion intensities:
|
296
|
-
sadness: {response['sadness']},
|
297
|
-
joy: {response['joy']},
|
298
|
-
fear: {response['fear']},
|
299
|
-
disgust: {response['disgust']},
|
300
|
-
anger: {response['anger']},
|
301
|
-
surprise: {response['surprise']}""")
|
302
278
|
|
303
|
-
await self.memory.update("emotion", {"sadness": int(response["sadness"]), "joy": int(response["joy"]), "fear": int(response["fear"]), "disgust": int(response["disgust"]), "anger": int(response["anger"]), "surprise": int(response["surprise"])})
|
304
|
-
|
279
|
+
await self.memory.status.update("emotion", {"sadness": int(response["sadness"]), "joy": int(response["joy"]), "fear": int(response["fear"]), "disgust": int(response["disgust"]), "anger": int(response["anger"]), "surprise": int(response["surprise"])})
|
280
|
+
await self.memory.status.update("emotion_types", str(response["word"]))
|
281
|
+
return response["conclusion"]
|