pycityagent 2.0.0a52__cp312-cp312-macosx_11_0_arm64.whl → 2.0.0a53__cp312-cp312-macosx_11_0_arm64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pycityagent/agent/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
@@ -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"]
|