pycityagent 2.0.0a52__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 -9
- pycityagent/workflow/block.py +11 -4
- {pycityagent-2.0.0a52.dist-info → pycityagent-2.0.0a53.dist-info}/METADATA +1 -1
- {pycityagent-2.0.0a52.dist-info → pycityagent-2.0.0a53.dist-info}/RECORD +35 -35
- pycityagent/cityagent/blocks/time_block.py +0 -116
- {pycityagent-2.0.0a52.dist-info → pycityagent-2.0.0a53.dist-info}/LICENSE +0 -0
- {pycityagent-2.0.0a52.dist-info → pycityagent-2.0.0a53.dist-info}/WHEEL +0 -0
- {pycityagent-2.0.0a52.dist-info → pycityagent-2.0.0a53.dist-info}/entry_points.txt +0 -0
- {pycityagent-2.0.0a52.dist-info → pycityagent-2.0.0a53.dist-info}/top_level.txt +0 -0
@@ -18,6 +18,8 @@ Available options: {options}
|
|
18
18
|
Current location: {current_location}
|
19
19
|
Current time: {current_time}
|
20
20
|
Current Environment: {environment}
|
21
|
+
Your emotion: {emotion_types}
|
22
|
+
Your thought: {thought}
|
21
23
|
|
22
24
|
Please evaluate and select the most appropriate option based on these three dimensions:
|
23
25
|
1. Attitude: Personal preference and evaluation of the option
|
@@ -26,7 +28,7 @@ Please evaluate and select the most appropriate option based on these three dime
|
|
26
28
|
|
27
29
|
Please return the evaluation results in JSON format (Do not return any other text):
|
28
30
|
{{
|
29
|
-
"selected_option": "Select the most suitable option from available
|
31
|
+
"selected_option": "Select the most suitable option from available options",
|
30
32
|
"evaluation": {{
|
31
33
|
"attitude": "Attitude score for the option (0-1)",
|
32
34
|
"subjective_norm": "Subjective norm score (0-1)",
|
@@ -42,6 +44,8 @@ Selected plan: {selected_option}
|
|
42
44
|
Current location: {current_location}
|
43
45
|
Current time: {current_time}
|
44
46
|
Current Environment: {environment}
|
47
|
+
Your emotion: {emotion_types}
|
48
|
+
Your thought: {thought}
|
45
49
|
|
46
50
|
Please generate specific execution steps and return in JSON format:
|
47
51
|
{{
|
@@ -148,26 +152,20 @@ Example outputs (Do not return any other text):
|
|
148
152
|
"""
|
149
153
|
|
150
154
|
class PlanBlock(Block):
|
151
|
-
configurable_fields: List[str] = ["
|
155
|
+
configurable_fields: List[str] = ["max_plan_steps"]
|
152
156
|
default_values = {
|
153
|
-
"guidance_options": {
|
154
|
-
"hungry": ['Eat at home', 'Eat outside'],
|
155
|
-
"tired": ['Sleep', 'Take a nap'],
|
156
|
-
"safe": ['Work'],
|
157
|
-
"social": ['Online social', 'Shopping'],
|
158
|
-
"whatever": ['Learning', 'Entertainment', 'Hang out', 'Exercise']
|
159
|
-
},
|
160
157
|
"max_plan_steps": 6
|
161
158
|
}
|
159
|
+
fields_description = {
|
160
|
+
"max_plan_steps": "The maximum number of steps in a plan"
|
161
|
+
}
|
162
162
|
|
163
163
|
def __init__(self, llm: LLM, memory: Memory, simulator: Simulator):
|
164
|
-
super().__init__("PlanBlock", llm, memory, simulator)
|
164
|
+
super().__init__("PlanBlock", llm=llm, memory=memory, simulator=simulator)
|
165
165
|
self.guidance_prompt = FormatPrompt(template=GUIDANCE_SELECTION_PROMPT)
|
166
166
|
self.detail_prompt = FormatPrompt(template=DETAILED_PLAN_PROMPT)
|
167
167
|
self.trigger_time = 0
|
168
168
|
self.token_consumption = 0
|
169
|
-
|
170
|
-
# configurable fields
|
171
169
|
self.guidance_options = {
|
172
170
|
"hungry": ['Eat at home', 'Eat outside'],
|
173
171
|
"tired": ['Sleep', 'Take a nap'],
|
@@ -175,30 +173,31 @@ class PlanBlock(Block):
|
|
175
173
|
"social": ['Online social', 'Shopping'],
|
176
174
|
"whatever": ['Learning', 'Entertainment', 'Hang out', 'Exercise']
|
177
175
|
}
|
176
|
+
|
177
|
+
# configurable fields
|
178
178
|
self.max_plan_steps = 6
|
179
179
|
|
180
180
|
async def select_guidance(self, current_need: str) -> Dict:
|
181
|
-
"""
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
position_now = await self.memory.get("position")
|
187
|
-
home_location = await self.memory.get("home")
|
188
|
-
work_location = await self.memory.get("work")
|
181
|
+
"""Select guidance plan"""
|
182
|
+
position_now = await self.memory.status.get("position")
|
183
|
+
home_location = await self.memory.status.get("home")
|
184
|
+
work_location = await self.memory.status.get("work")
|
189
185
|
current_location = "Out"
|
190
186
|
if 'aoi_position' in position_now and position_now['aoi_position'] == home_location['aoi_position']:
|
191
187
|
current_location = "At home"
|
192
188
|
elif 'aoi_position' in position_now and position_now['aoi_position'] == work_location['aoi_position']:
|
193
189
|
current_location = "At workplace"
|
194
190
|
current_time = await self.simulator.get_time(format_time=True)
|
195
|
-
environment = await self.memory.get("environment")
|
191
|
+
environment = await self.memory.status.get("environment")
|
192
|
+
options = self.guidance_options.get(current_need, [])
|
196
193
|
self.guidance_prompt.format(
|
197
194
|
current_need=current_need,
|
198
195
|
options=options,
|
199
196
|
current_location=current_location,
|
200
197
|
current_time=current_time,
|
201
|
-
environment=environment
|
198
|
+
environment=environment,
|
199
|
+
emotion_types=await self.memory.status.get("emotion_types"),
|
200
|
+
thought=await self.memory.status.get("thought")
|
202
201
|
)
|
203
202
|
|
204
203
|
response = await self.llm.atext_request(
|
@@ -207,32 +206,30 @@ class PlanBlock(Block):
|
|
207
206
|
|
208
207
|
try:
|
209
208
|
result = json.loads(self.clean_json_response(response)) # type: ignore
|
210
|
-
if result['selected_option'] not in options:
|
211
|
-
result['selected_option'] = random.choice(options)
|
212
|
-
logger.info(f"\n=== Plan Selection ===")
|
213
|
-
logger.info(f"Selected Plan: {result['selected_option']}")
|
214
209
|
return result
|
215
210
|
except Exception as e:
|
216
211
|
logger.warning(f"Error parsing guidance selection response: {str(e)}")
|
217
212
|
return None # type: ignore
|
218
213
|
|
219
214
|
async def generate_detailed_plan(self, current_need: str, selected_option: str) -> Dict:
|
220
|
-
"""
|
221
|
-
position_now = await self.memory.get("position")
|
222
|
-
home_location = await self.memory.get("home")
|
223
|
-
work_location = await self.memory.get("work")
|
215
|
+
"""Generate detailed execution plan"""
|
216
|
+
position_now = await self.memory.status.get("position")
|
217
|
+
home_location = await self.memory.status.get("home")
|
218
|
+
work_location = await self.memory.status.get("work")
|
224
219
|
current_location = "Out"
|
225
220
|
if 'aoi_position' in position_now and position_now['aoi_position'] == home_location['aoi_position']:
|
226
221
|
current_location = "At home"
|
227
222
|
elif 'aoi_position' in position_now and position_now['aoi_position'] == work_location['aoi_position']:
|
228
223
|
current_location = "At workplace"
|
229
224
|
current_time = await self.simulator.get_time(format_time=True)
|
230
|
-
environment = await self.memory.get("environment")
|
225
|
+
environment = await self.memory.status.get("environment")
|
231
226
|
self.detail_prompt.format(
|
232
227
|
selected_option=selected_option,
|
233
228
|
current_location=current_location,
|
234
229
|
current_time=current_time,
|
235
230
|
environment=environment,
|
231
|
+
emotion_types=await self.memory.status.get("emotion_types"),
|
232
|
+
thought=await self.memory.status.get("thought"),
|
236
233
|
max_plan_steps=self.max_plan_steps
|
237
234
|
)
|
238
235
|
|
@@ -250,36 +247,25 @@ class PlanBlock(Block):
|
|
250
247
|
async def forward(self):
|
251
248
|
self.trigger_time += 1
|
252
249
|
consumption_start = self.llm.prompt_tokens_used + self.llm.completion_tokens_used
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
await self.memory.update("current_plan", [])
|
257
|
-
await self.memory.update("current_step", {"intention": "", "type": ""})
|
258
|
-
return
|
259
|
-
|
260
|
-
# 第一步:选择指导方案
|
250
|
+
|
251
|
+
# Step 1: Select guidance plan
|
252
|
+
current_need = await self.memory.status.get("current_need")
|
261
253
|
guidance_result = await self.select_guidance(current_need)
|
262
254
|
if not guidance_result:
|
263
255
|
return
|
264
256
|
|
265
|
-
#
|
257
|
+
# Step 2: Generate detailed plan
|
266
258
|
detailed_plan = await self.generate_detailed_plan(
|
267
259
|
current_need,
|
268
260
|
guidance_result["selected_option"]
|
269
261
|
)
|
270
262
|
|
271
263
|
if not detailed_plan or "plan" not in detailed_plan:
|
272
|
-
await self.memory.update("current_plan", [])
|
273
|
-
await self.memory.update("current_step", {"intention": "", "type": ""})
|
264
|
+
await self.memory.status.update("current_plan", [])
|
265
|
+
await self.memory.status.update("current_step", {"intention": "", "type": ""})
|
274
266
|
return
|
275
|
-
logger.info("\n=== Plan Generation ===")
|
276
|
-
logger.info(f"Target: {detailed_plan['plan']['target']}")
|
277
|
-
logger.info("\nExecution Steps:")
|
278
|
-
for i, step in enumerate(detailed_plan['plan']['steps'], 1):
|
279
|
-
logger.info(f"{i}. {step['intention']} ({step['type']})")
|
280
|
-
logger.info("===============\n")
|
281
267
|
|
282
|
-
#
|
268
|
+
# Step 3: Update plan and current step
|
283
269
|
steps = detailed_plan["plan"]["steps"]
|
284
270
|
for step in steps:
|
285
271
|
step["evaluation"] = {"status": "pending", "details": ""}
|
@@ -288,22 +274,24 @@ class PlanBlock(Block):
|
|
288
274
|
"target": detailed_plan["plan"]["target"],
|
289
275
|
"steps": steps,
|
290
276
|
"completed": False,
|
291
|
-
"
|
277
|
+
"failed": False,
|
278
|
+
"stream_nodes": [],
|
279
|
+
"guidance": guidance_result # Save the evaluation result of the plan selection
|
292
280
|
}
|
293
281
|
formated_steps = "\n".join([f"{i}. {step['intention']}" for i, step in enumerate(plan['steps'], 1)])
|
294
282
|
formated_plan = f"""
|
295
|
-
|
296
|
-
|
283
|
+
Overall Target: {plan['target']}
|
284
|
+
Execution Steps: \n{formated_steps}
|
297
285
|
"""
|
298
286
|
plan['start_time'] = await self.simulator.get_time(format_time=True)
|
299
|
-
await self.memory.update("current_plan", plan)
|
300
|
-
await self.memory.update("current_step", steps[0] if steps else {"intention": "", "type": ""})
|
301
|
-
await self.memory.update("execution_context", {'plan': formated_plan})
|
287
|
+
await self.memory.status.update("current_plan", plan)
|
288
|
+
await self.memory.status.update("current_step", steps[0] if steps else {"intention": "", "type": ""})
|
289
|
+
await self.memory.status.update("execution_context", {'plan': formated_plan})
|
302
290
|
|
303
291
|
consumption_end = self.llm.prompt_tokens_used + self.llm.completion_tokens_used
|
304
292
|
self.token_consumption += consumption_end - consumption_start
|
305
293
|
|
306
294
|
def clean_json_response(self, response: str) -> str:
|
307
|
-
"""
|
295
|
+
"""Clean special characters in LLM response"""
|
308
296
|
response = response.replace('```json', '').replace('```', '')
|
309
297
|
return response.strip()
|
@@ -23,8 +23,8 @@ class MessagePromptManager:
|
|
23
23
|
async def get_prompt(self, memory, step: Dict[str, Any], target: str) -> str:
|
24
24
|
"""在这里改给模板输入的数据"""
|
25
25
|
# 获取数据
|
26
|
-
relationships = await memory.get("relationships") or {}
|
27
|
-
chat_histories = await memory.get("chat_histories") or {}
|
26
|
+
relationships = await memory.status.get("relationships") or {}
|
27
|
+
chat_histories = await memory.status.get("chat_histories") or {}
|
28
28
|
|
29
29
|
# 构建讨论话题约束
|
30
30
|
discussion_constraint = ""
|
@@ -34,12 +34,14 @@ class MessagePromptManager:
|
|
34
34
|
|
35
35
|
# 格式化提示
|
36
36
|
self.format_prompt.format(
|
37
|
-
gender=await memory.get("gender") or "",
|
38
|
-
education=await memory.get("education") or "",
|
39
|
-
personality=await memory.get("personality") or "",
|
40
|
-
occupation=await memory.get("occupation") or "",
|
37
|
+
gender=await memory.status.get("gender") or "",
|
38
|
+
education=await memory.status.get("education") or "",
|
39
|
+
personality=await memory.status.get("personality") or "",
|
40
|
+
occupation=await memory.status.get("occupation") or "",
|
41
41
|
relationship_score=relationships.get(target, 50),
|
42
42
|
intention=step.get("intention", ""),
|
43
|
+
emotion_types=await memory.status.get("emotion_types"),
|
44
|
+
thought=await memory.status.get("thought"),
|
43
45
|
chat_history=chat_histories.get(target, "") if isinstance(chat_histories, dict) else "",
|
44
46
|
discussion_constraint=discussion_constraint
|
45
47
|
)
|
@@ -52,47 +54,57 @@ class SocialNoneBlock(Block):
|
|
52
54
|
NoneBlock
|
53
55
|
"""
|
54
56
|
def __init__(self, llm: LLM, memory: Memory):
|
55
|
-
super().__init__("NoneBlock", llm, memory)
|
57
|
+
super().__init__("NoneBlock", llm=llm, memory=memory)
|
56
58
|
self.description = "Handle all other cases"
|
57
59
|
self.guidance_prompt = FormatPrompt(template=TIME_ESTIMATE_PROMPT)
|
58
60
|
|
59
61
|
async def forward(self, step, context):
|
60
|
-
self.guidance_prompt.format(
|
62
|
+
self.guidance_prompt.format(plan=context['plan'],
|
63
|
+
intention=step['intention'],
|
64
|
+
emotion_types=await self.memory.status.get("emotion_types"))
|
61
65
|
result = await self.llm.atext_request(self.guidance_prompt.to_dialog())
|
62
66
|
result = clean_json_response(result)
|
63
67
|
try:
|
64
68
|
result = json.loads(result)
|
69
|
+
node_id = await self.memory.stream.add_social(description=f"I {step['intention']}")
|
65
70
|
return {
|
66
71
|
'success': True,
|
67
|
-
'evaluation': f'
|
68
|
-
'consumed_time': result['time']
|
72
|
+
'evaluation': f'Finished {step["intention"]}',
|
73
|
+
'consumed_time': result['time'],
|
74
|
+
'node_id': node_id
|
69
75
|
}
|
70
76
|
except Exception as e:
|
71
77
|
logger.warning(f"解析时间评估响应时发生错误: {str(e)}, 原始结果: {result}")
|
78
|
+
node_id = await self.memory.stream.add_social(description=f"I failed to execute {step['intention']}")
|
72
79
|
return {
|
73
80
|
'success': False,
|
74
|
-
'evaluation': f'
|
75
|
-
'consumed_time':
|
81
|
+
'evaluation': f'Failed to execute {step["intention"]}',
|
82
|
+
'consumed_time': 5,
|
83
|
+
'node_id': node_id
|
76
84
|
}
|
77
85
|
|
78
86
|
class FindPersonBlock(Block):
|
79
87
|
"""寻找社交对象"""
|
80
88
|
def __init__(self, llm: LLM, memory: Memory, simulator: Simulator):
|
81
|
-
super().__init__("FindPersonBlock", llm, memory, simulator)
|
89
|
+
super().__init__("FindPersonBlock", llm=llm, memory=memory, simulator=simulator)
|
82
90
|
self.description = "Find a suitable person to socialize with"
|
83
91
|
|
84
92
|
self.prompt = """
|
85
93
|
Based on the following information, help me select the most suitable friend to interact with:
|
86
94
|
|
87
|
-
1.
|
95
|
+
1. Your Profile:
|
88
96
|
- Gender: {gender}
|
89
97
|
- Education: {education}
|
90
98
|
- Personality: {personality}
|
91
99
|
- Occupation: {occupation}
|
92
100
|
|
93
|
-
2.
|
101
|
+
2. Your Current Intention: {intention}
|
94
102
|
|
95
|
-
3.
|
103
|
+
3. Your Current Emotion: {emotion_types}
|
104
|
+
|
105
|
+
4. Your Current Thought: {thought}
|
106
|
+
|
107
|
+
5. Your Friends List (shown as index-to-relationship pairs):
|
96
108
|
{friend_info}
|
97
109
|
Note: For each friend, the relationship strength (0-100) indicates how close we are
|
98
110
|
|
@@ -112,26 +124,20 @@ class FindPersonBlock(Block):
|
|
112
124
|
|
113
125
|
async def forward(self, step: Dict[str, Any], context: Optional[Dict] = None) -> Dict[str, Any]:
|
114
126
|
try:
|
115
|
-
#
|
116
|
-
|
117
|
-
|
118
|
-
"education": await self.memory.get("education"),
|
119
|
-
"personality": await self.memory.get("personality"),
|
120
|
-
"occupation": await self.memory.get("occupation")
|
121
|
-
}
|
122
|
-
|
123
|
-
# 获取朋友列表和关系强度
|
124
|
-
friends = await self.memory.get("friends") or []
|
125
|
-
relationships = await self.memory.get("relationships") or {}
|
127
|
+
# Get friends list and relationship strength
|
128
|
+
friends = await self.memory.status.get("friends") or []
|
129
|
+
relationships = await self.memory.status.get("relationships") or {}
|
126
130
|
|
127
131
|
if not friends:
|
132
|
+
node_id = await self.memory.stream.add_social(description=f"I can't find any friends to socialize with.")
|
128
133
|
return {
|
129
134
|
'success': False,
|
130
135
|
'evaluation': 'No friends found in social network',
|
131
|
-
'consumed_time': 5
|
136
|
+
'consumed_time': 5,
|
137
|
+
'node_id': node_id
|
132
138
|
}
|
133
139
|
|
134
|
-
#
|
140
|
+
# Create a list of friends with all information
|
135
141
|
friend_info = []
|
136
142
|
index_to_uuid = {}
|
137
143
|
|
@@ -143,57 +149,63 @@ class FindPersonBlock(Block):
|
|
143
149
|
})
|
144
150
|
index_to_uuid[i] = friend_id
|
145
151
|
|
146
|
-
#
|
152
|
+
# Format friend information for easier reading
|
147
153
|
formatted_friend_info = {
|
148
154
|
i: {'relationship_strength': info['relationship_strength']}
|
149
155
|
for i, info in enumerate(friend_info)
|
150
156
|
}
|
151
157
|
|
152
|
-
#
|
158
|
+
# Format the prompt
|
153
159
|
formatted_prompt = FormatPrompt(self.prompt)
|
154
160
|
formatted_prompt.format(
|
155
|
-
gender=str(await self.memory.get("gender")),
|
156
|
-
education=str(await self.memory.get("education")),
|
157
|
-
personality=str(await self.memory.get("personality")),
|
158
|
-
occupation=str(await self.memory.get("occupation")),
|
161
|
+
gender=str(await self.memory.status.get("gender")),
|
162
|
+
education=str(await self.memory.status.get("education")),
|
163
|
+
personality=str(await self.memory.status.get("personality")),
|
164
|
+
occupation=str(await self.memory.status.get("occupation")),
|
159
165
|
intention=str(step.get("intention", "socialize")),
|
166
|
+
emotion_types=str(await self.memory.status.get("emotion_types")),
|
167
|
+
thought=str(await self.memory.status.get("thought")),
|
160
168
|
friend_info=str(formatted_friend_info)
|
161
169
|
)
|
162
170
|
|
163
|
-
#
|
171
|
+
# Get LLM response
|
164
172
|
response = await self.llm.atext_request(formatted_prompt.to_dialog(), timeout=300)
|
165
173
|
|
166
174
|
try:
|
167
|
-
#
|
175
|
+
# Parse the response
|
168
176
|
mode, friend_index = eval(response)
|
169
177
|
|
170
|
-
#
|
178
|
+
# Validate the response format
|
171
179
|
if not isinstance(mode, str) or mode not in ['online', 'offline']:
|
172
180
|
raise ValueError("Invalid mode")
|
173
181
|
if not isinstance(friend_index, int) or friend_index not in index_to_uuid:
|
174
182
|
raise ValueError("Invalid friend index")
|
175
183
|
|
176
|
-
#
|
184
|
+
# Convert index to UUID
|
177
185
|
target = index_to_uuid[friend_index]
|
178
186
|
context['target']=target
|
179
187
|
except Exception as e:
|
180
|
-
#
|
188
|
+
# If parsing fails, select the friend with the strongest relationship as the default option
|
181
189
|
target = max(relationships.items(), key=lambda x: x[1])[0] if relationships else friends[0]
|
182
190
|
mode = 'online'
|
183
|
-
|
191
|
+
|
192
|
+
node_id = await self.memory.stream.add_social(description=f"I selected the friend {target} for {mode} interaction")
|
184
193
|
return {
|
185
194
|
'success': True,
|
186
195
|
'evaluation': f'Selected friend {target} for {mode} interaction',
|
187
196
|
'consumed_time': 15,
|
188
197
|
'mode': mode,
|
189
|
-
'target': target
|
198
|
+
'target': target,
|
199
|
+
'node_id': node_id
|
190
200
|
}
|
191
201
|
|
192
202
|
except Exception as e:
|
203
|
+
node_id = await self.memory.stream.add_social(description=f"I can't find any friends to socialize with.")
|
193
204
|
return {
|
194
205
|
'success': False,
|
195
206
|
'evaluation': f'Error in finding person: {str(e)}',
|
196
|
-
'consumed_time': 5
|
207
|
+
'consumed_time': 5,
|
208
|
+
'node_id': node_id
|
197
209
|
}
|
198
210
|
|
199
211
|
class MessageBlock(Block):
|
@@ -209,7 +221,7 @@ class MessageBlock(Block):
|
|
209
221
|
}
|
210
222
|
|
211
223
|
def __init__(self, agent, llm: LLM, memory: Memory, simulator: Simulator):
|
212
|
-
super().__init__("MessageBlock", llm, memory, simulator)
|
224
|
+
super().__init__("MessageBlock", llm=llm, memory=memory, simulator=simulator)
|
213
225
|
self.agent = agent
|
214
226
|
self.description = "Generate and send a message to someone"
|
215
227
|
self.find_person_block = FindPersonBlock(llm, memory, simulator)
|
@@ -219,6 +231,9 @@ class MessageBlock(Block):
|
|
219
231
|
As a {gender} {occupation} with {education} education and {personality} personality,
|
220
232
|
generate a message for a friend (relationship strength: {relationship_score}/100)
|
221
233
|
about {intention}.
|
234
|
+
|
235
|
+
Your current emotion: {emotion_types}
|
236
|
+
Your current thought: {thought}
|
222
237
|
|
223
238
|
Previous chat history:
|
224
239
|
{chat_history}
|
@@ -256,7 +271,7 @@ class MessageBlock(Block):
|
|
256
271
|
}
|
257
272
|
target = result['target']
|
258
273
|
|
259
|
-
#
|
274
|
+
# Get formatted prompt using prompt manager
|
260
275
|
formatted_prompt = await self.prompt_manager.get_prompt(
|
261
276
|
self.memory,
|
262
277
|
step,
|
@@ -269,7 +284,7 @@ class MessageBlock(Block):
|
|
269
284
|
message = "Hello! How are you?"
|
270
285
|
|
271
286
|
# Update chat history with proper format
|
272
|
-
chat_histories = await self.memory.get("chat_histories") or {}
|
287
|
+
chat_histories = await self.memory.status.get("chat_histories") or {}
|
273
288
|
if not isinstance(chat_histories, dict):
|
274
289
|
chat_histories = {}
|
275
290
|
if target not in chat_histories:
|
@@ -278,23 +293,27 @@ class MessageBlock(Block):
|
|
278
293
|
chat_histories[target] += ","
|
279
294
|
chat_histories[target] += f"me: {message}"
|
280
295
|
|
281
|
-
await self.memory.update("chat_histories", chat_histories)
|
296
|
+
await self.memory.status.update("chat_histories", chat_histories)
|
282
297
|
|
283
298
|
# Send message
|
284
299
|
serialized_message = self._serialize_message(message, 1)
|
300
|
+
node_id = await self.memory.stream.add_social(description=f"I sent a message to {target}: {message}")
|
285
301
|
return {
|
286
302
|
'success': True,
|
287
303
|
'evaluation': f'Sent message to {target}: {message}',
|
288
304
|
'consumed_time': 10,
|
289
305
|
'message': message,
|
290
|
-
'target': target
|
306
|
+
'target': target,
|
307
|
+
'node_id': node_id
|
291
308
|
}
|
292
309
|
|
293
310
|
except Exception as e:
|
311
|
+
node_id = await self.memory.stream.add_social(description=f"I can't send a message to {target}")
|
294
312
|
return {
|
295
313
|
'success': False,
|
296
314
|
'evaluation': f'Error in sending message: {str(e)}',
|
297
|
-
'consumed_time': 5
|
315
|
+
'consumed_time': 5,
|
316
|
+
'node_id': node_id
|
298
317
|
}
|
299
318
|
|
300
319
|
class SocialBlock(Block):
|
@@ -304,10 +323,10 @@ class SocialBlock(Block):
|
|
304
323
|
noneblock: SocialNoneBlock
|
305
324
|
|
306
325
|
def __init__(self, agent, llm: LLM, memory: Memory, simulator: Simulator):
|
307
|
-
super().__init__("SocialBlock", llm, memory, simulator)
|
326
|
+
super().__init__("SocialBlock", llm=llm, memory=memory, simulator=simulator)
|
308
327
|
self.find_person_block = FindPersonBlock(llm, memory, simulator)
|
309
328
|
self.message_block = MessageBlock(agent, llm, memory, simulator)
|
310
|
-
self.noneblock=SocialNoneBlock(llm,memory)
|
329
|
+
self.noneblock=SocialNoneBlock(llm, memory)
|
311
330
|
self.dispatcher = BlockDispatcher(llm)
|
312
331
|
|
313
332
|
self.trigger_time = 0
|
@@ -62,12 +62,10 @@ class FirmAgent(InstitutionAgent):
|
|
62
62
|
|
63
63
|
async def forward(self):
|
64
64
|
if await self.month_trigger():
|
65
|
-
employees = await self.memory.get("employees")
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
break
|
70
|
-
await asyncio.sleep(1)
|
65
|
+
employees = await self.memory.status.get("employees")
|
66
|
+
agents_forward = []
|
67
|
+
if not np.all(np.array(agents_forward) > self.forward_times):
|
68
|
+
return
|
71
69
|
goods_demand = await self.gather_messages(employees, "goods_demand")
|
72
70
|
goods_consumption = await self.gather_messages(
|
73
71
|
employees, "goods_consumption"
|
@@ -90,6 +88,7 @@ class FirmAgent(InstitutionAgent):
|
|
90
88
|
await self.send_message_to_agent(
|
91
89
|
uuid,
|
92
90
|
f"work_skill@{max(skill*(1 + np.random.uniform(0, max_change_rate*self.max_wage_inflation)), 1)}",
|
91
|
+
"economy",
|
93
92
|
)
|
94
93
|
price = await self.economy_client.get(self._agent_id, "price")
|
95
94
|
await self.economy_client.update(
|
@@ -109,5 +108,5 @@ class FirmAgent(InstitutionAgent):
|
|
109
108
|
self.forward_times += 1
|
110
109
|
for uuid in employees:
|
111
110
|
await self.send_message_to_agent(
|
112
|
-
uuid, f"firm_forward@{self.forward_times}"
|
111
|
+
uuid, f"firm_forward@{self.forward_times}", "economy"
|
113
112
|
)
|
@@ -53,13 +53,11 @@ class GovernmentAgent(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
|
-
|
61
|
-
await asyncio.sleep(1)
|
62
|
-
citizens_agent_id = await self.memory.get("citizens_agent_id")
|
56
|
+
citizens = await self.memory.status.get("citizens")
|
57
|
+
agents_forward = await self.gather_messages(citizens, "forward")
|
58
|
+
if not np.all(np.array(agents_forward) > self.forward_times):
|
59
|
+
return
|
60
|
+
citizens_agent_id = await self.memory.status.get("citizens_agent_id")
|
63
61
|
incomes = await self.gather_messages(citizens, "income_currency") # uuid
|
64
62
|
_, post_tax_incomes = await self.economy_client.calculate_taxes_due(
|
65
63
|
self._agent_id, citizens_agent_id, incomes, enable_redistribution=False
|
@@ -68,9 +66,9 @@ class GovernmentAgent(InstitutionAgent):
|
|
68
66
|
citizens, incomes, post_tax_incomes
|
69
67
|
):
|
70
68
|
tax_paid = income - post_tax_income
|
71
|
-
await self.send_message_to_agent(uuid, f"tax_paid@{tax_paid}")
|
69
|
+
await self.send_message_to_agent(uuid, f"tax_paid@{tax_paid}", "economy")
|
72
70
|
self.forward_times += 1
|
73
71
|
for uuid in citizens:
|
74
72
|
await self.send_message_to_agent(
|
75
|
-
uuid, f"government_forward@{self.forward_times}"
|
73
|
+
uuid, f"government_forward@{self.forward_times}", "economy"
|
76
74
|
)
|