pycityagent 2.0.0a51__cp39-cp39-macosx_11_0_arm64.whl → 2.0.0a53__cp39-cp39-macosx_11_0_arm64.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. pycityagent/agent/agent.py +48 -62
  2. pycityagent/agent/agent_base.py +66 -53
  3. pycityagent/cityagent/bankagent.py +5 -7
  4. pycityagent/cityagent/blocks/__init__.py +0 -2
  5. pycityagent/cityagent/blocks/cognition_block.py +149 -172
  6. pycityagent/cityagent/blocks/economy_block.py +90 -129
  7. pycityagent/cityagent/blocks/mobility_block.py +56 -29
  8. pycityagent/cityagent/blocks/needs_block.py +163 -145
  9. pycityagent/cityagent/blocks/other_block.py +17 -9
  10. pycityagent/cityagent/blocks/plan_block.py +44 -56
  11. pycityagent/cityagent/blocks/social_block.py +70 -51
  12. pycityagent/cityagent/blocks/utils.py +2 -0
  13. pycityagent/cityagent/firmagent.py +6 -7
  14. pycityagent/cityagent/governmentagent.py +7 -9
  15. pycityagent/cityagent/memory_config.py +48 -48
  16. pycityagent/cityagent/nbsagent.py +6 -29
  17. pycityagent/cityagent/societyagent.py +204 -119
  18. pycityagent/environment/sim/client.py +10 -1
  19. pycityagent/environment/sim/clock_service.py +2 -2
  20. pycityagent/environment/sim/pause_service.py +61 -0
  21. pycityagent/environment/simulator.py +17 -12
  22. pycityagent/llm/embeddings.py +0 -24
  23. pycityagent/memory/faiss_query.py +29 -26
  24. pycityagent/memory/memory.py +720 -272
  25. pycityagent/pycityagent-sim +0 -0
  26. pycityagent/simulation/agentgroup.py +92 -99
  27. pycityagent/simulation/simulation.py +115 -40
  28. pycityagent/tools/tool.py +7 -10
  29. pycityagent/workflow/block.py +11 -4
  30. {pycityagent-2.0.0a51.dist-info → pycityagent-2.0.0a53.dist-info}/METADATA +2 -2
  31. {pycityagent-2.0.0a51.dist-info → pycityagent-2.0.0a53.dist-info}/RECORD +35 -35
  32. {pycityagent-2.0.0a51.dist-info → pycityagent-2.0.0a53.dist-info}/WHEEL +1 -1
  33. pycityagent/cityagent/blocks/time_block.py +0 -116
  34. {pycityagent-2.0.0a51.dist-info → pycityagent-2.0.0a53.dist-info}/LICENSE +0 -0
  35. {pycityagent-2.0.0a51.dist-info → pycityagent-2.0.0a53.dist-info}/entry_points.txt +0 -0
  36. {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.llm import 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.last_trigger_time = None
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 check_trigger(self):
39
- now_time = await self.simulator.get_time()
40
- if self.last_trigger_time is None or now_time - self.last_trigger_time > self.time_diff:
41
- self.last_trigger_time = now_time
42
- return True
43
- return False
44
-
45
- async def attitude_update(self, topic):
46
- description_prompt = """
47
- You are a {gender}, aged {age}, belonging to the {race} race and identifying as {religion}.
48
- Your marital status is {marital_status}, and you currently reside in a {residence} area.
49
- Your occupation is {occupation}, and your education level is {education}.
50
- You are {personality}, with a consumption level of {consumption} and a family consumption level of {family_consumption}.
51
- Your income is {income}, and you are skilled in {skill}.
52
- My current emotion intensities are (0 meaning not at all, 10 meaning very much):
53
- sadness: {sadness}, joy: {joy}, fear: {fear}, disgust: {disgust}, anger: {anger}, surprise: {surprise}.
54
- You have the following thoughts: {thought}.
55
- In the following 21 words, I have chosen {emotion_types} to represent your current status:
56
- Joy, Distress, Resentment, Pity, Hope, Fear, Satisfaction, Relief, Disappointment, Pride, Admiration, Shame, Reproach, Liking, Disliking, Gratitude, Anger, Gratification, Remorse, Love, Hate.
57
- """
58
- incident_list = await self.memory.get("incident")
59
- if incident_list:
60
- incident_prompt = "Today, these incidents happened:"
61
- for incident in incident_list:
62
- incident_prompt += incident
63
- else:
64
- incident_prompt = "No incidents happened today."
65
- attitude = await self.memory.get("attitude")
66
- if topic in attitude:
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
- else:
75
- problem_prompt = (
76
- f"You need to decide your attitude towards topic: {topic}, "
77
- "which you have not rated your attitude towards this topic yet. "
78
- "(0 meaning oppose, 10 meaning support). "
79
- "Please return a new attitude rating (0-10, smaller meaning oppose, larger meaning support) in JSON format, and explain, e.g. {{\"attitude\": 5}}"
80
- )
81
- question_prompt = description_prompt + incident_prompt + problem_prompt
82
- question_prompt = FormatPrompt(question_prompt)
83
- emotion = await self.memory.get("emotion")
84
- sadness = emotion["sadness"]
85
- joy = emotion["joy"]
86
- fear = emotion["fear"]
87
- disgust = emotion["disgust"]
88
- anger = emotion["anger"]
89
- surprise = emotion["surprise"]
90
-
91
- question_prompt.format(
92
- gender=await self.memory.get("gender"),
93
- age=await self.memory.get("age"),
94
- race=await self.memory.get("race"),
95
- religion=await self.memory.get("religion"),
96
- marital_status=await self.memory.get("marital_status"),
97
- residence=await self.memory.get("residence"),
98
- occupation=await self.memory.get("occupation"),
99
- education=await self.memory.get("education"),
100
- personality=await self.memory.get("personality"),
101
- consumption=await self.memory.get("consumption"),
102
- family_consumption=await self.memory.get("family_consumption"),
103
- income=await self.memory.get("income"),
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 forward(self): #每日结算
132
- whether_trigger = await self.check_trigger()
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
- incident_list = await self.memory.get("incident")
151
- if incident_list:
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 reconsider your emotion intensities:
159
- sadness, joy, fear, disgust, anger, surprise (0 meaning not at all, 10 meaning very much).
160
- Also summerize you current thoughts, and choose a word to describe your status: Joy, Distress, Resentment, Pity, Hope, Fear, Satisfaction, Relief, Disappointment, Pride, Admiration, Shame, Reproach, Liking, Disliking, Gratitude, Anger, Gratification, Remorse, Love, Hate.
161
- Return in JSON format, e.g. {{"sadness": 5, "joy": 5, "fear": 5, "disgust": 5, "anger": 5, "surprise": 5, "thought": "Currently nothing good or bad is happening, I think ....", "word": "Relief"}}"""
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
- await self.memory.update("incident", [])
218
- 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"])})
219
- await self.memory.update("thought", str(response["thought"]))
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 emotion_update(self, incident): #每日结算
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
- print(e)
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
- return
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"]