pycityagent 2.0.0a65__cp311-cp311-macosx_11_0_arm64.whl → 2.0.0a67__cp311-cp311-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 +157 -57
- pycityagent/agent/agent_base.py +316 -43
- pycityagent/cityagent/bankagent.py +49 -9
- pycityagent/cityagent/blocks/__init__.py +1 -2
- pycityagent/cityagent/blocks/cognition_block.py +54 -31
- pycityagent/cityagent/blocks/dispatcher.py +22 -17
- pycityagent/cityagent/blocks/economy_block.py +46 -32
- pycityagent/cityagent/blocks/mobility_block.py +209 -105
- pycityagent/cityagent/blocks/needs_block.py +101 -54
- pycityagent/cityagent/blocks/other_block.py +42 -33
- pycityagent/cityagent/blocks/plan_block.py +59 -42
- pycityagent/cityagent/blocks/social_block.py +167 -126
- pycityagent/cityagent/blocks/utils.py +13 -6
- pycityagent/cityagent/firmagent.py +17 -35
- pycityagent/cityagent/governmentagent.py +3 -3
- pycityagent/cityagent/initial.py +79 -49
- pycityagent/cityagent/memory_config.py +123 -94
- pycityagent/cityagent/message_intercept.py +0 -4
- pycityagent/cityagent/metrics.py +41 -0
- pycityagent/cityagent/nbsagent.py +24 -36
- pycityagent/cityagent/societyagent.py +9 -4
- pycityagent/cli/wrapper.py +2 -2
- pycityagent/economy/econ_client.py +407 -81
- pycityagent/environment/__init__.py +0 -3
- pycityagent/environment/sim/__init__.py +0 -3
- pycityagent/environment/sim/aoi_service.py +2 -2
- pycityagent/environment/sim/client.py +3 -31
- pycityagent/environment/sim/clock_service.py +2 -2
- pycityagent/environment/sim/lane_service.py +8 -8
- pycityagent/environment/sim/light_service.py +8 -8
- pycityagent/environment/sim/pause_service.py +9 -10
- pycityagent/environment/sim/person_service.py +20 -20
- pycityagent/environment/sim/road_service.py +2 -2
- pycityagent/environment/sim/sim_env.py +21 -5
- pycityagent/environment/sim/social_service.py +4 -4
- pycityagent/environment/simulator.py +249 -27
- pycityagent/environment/utils/__init__.py +2 -2
- pycityagent/environment/utils/geojson.py +2 -2
- pycityagent/environment/utils/grpc.py +4 -4
- pycityagent/environment/utils/map_utils.py +2 -2
- pycityagent/llm/embeddings.py +147 -28
- pycityagent/llm/llm.py +178 -111
- pycityagent/llm/llmconfig.py +5 -0
- pycityagent/llm/utils.py +4 -0
- pycityagent/memory/__init__.py +0 -4
- pycityagent/memory/const.py +2 -2
- pycityagent/memory/faiss_query.py +140 -61
- pycityagent/memory/memory.py +394 -91
- pycityagent/memory/memory_base.py +140 -34
- pycityagent/memory/profile.py +13 -13
- pycityagent/memory/self_define.py +13 -13
- pycityagent/memory/state.py +14 -14
- pycityagent/message/message_interceptor.py +253 -3
- pycityagent/message/messager.py +133 -6
- pycityagent/metrics/mlflow_client.py +47 -4
- pycityagent/pycityagent-sim +0 -0
- pycityagent/pycityagent-ui +0 -0
- pycityagent/simulation/__init__.py +3 -2
- pycityagent/simulation/agentgroup.py +150 -54
- pycityagent/simulation/simulation.py +276 -66
- pycityagent/survey/manager.py +45 -3
- pycityagent/survey/models.py +42 -2
- pycityagent/tools/__init__.py +1 -2
- pycityagent/tools/tool.py +93 -69
- pycityagent/utils/avro_schema.py +2 -2
- pycityagent/utils/parsers/code_block_parser.py +1 -1
- pycityagent/utils/parsers/json_parser.py +2 -2
- pycityagent/utils/parsers/parser_base.py +2 -2
- pycityagent/workflow/block.py +64 -13
- pycityagent/workflow/prompt.py +31 -23
- pycityagent/workflow/trigger.py +91 -24
- {pycityagent-2.0.0a65.dist-info → pycityagent-2.0.0a67.dist-info}/METADATA +2 -2
- pycityagent-2.0.0a67.dist-info/RECORD +97 -0
- pycityagent/environment/interact/__init__.py +0 -0
- pycityagent/environment/interact/interact.py +0 -198
- pycityagent/environment/message/__init__.py +0 -0
- pycityagent/environment/sence/__init__.py +0 -0
- pycityagent/environment/sence/static.py +0 -416
- pycityagent/environment/sidecar/__init__.py +0 -8
- pycityagent/environment/sidecar/sidecarv2.py +0 -109
- pycityagent/environment/sim/economy_services.py +0 -192
- pycityagent/metrics/utils/const.py +0 -0
- pycityagent-2.0.0a65.dist-info/RECORD +0 -105
- {pycityagent-2.0.0a65.dist-info → pycityagent-2.0.0a67.dist-info}/LICENSE +0 -0
- {pycityagent-2.0.0a65.dist-info → pycityagent-2.0.0a67.dist-info}/WHEEL +0 -0
- {pycityagent-2.0.0a65.dist-info → pycityagent-2.0.0a67.dist-info}/entry_points.txt +0 -0
- {pycityagent-2.0.0a65.dist-info → pycityagent-2.0.0a67.dist-info}/top_level.txt +0 -0
@@ -1,27 +1,31 @@
|
|
1
|
+
import json
|
2
|
+
import logging
|
3
|
+
|
4
|
+
from pycityagent.environment.simulator import Simulator
|
1
5
|
from pycityagent.llm import LLM
|
2
|
-
from pycityagent.workflow.block import Block
|
3
6
|
from pycityagent.memory import Memory
|
4
|
-
from pycityagent.
|
7
|
+
from pycityagent.workflow.block import Block
|
5
8
|
from pycityagent.workflow.prompt import FormatPrompt
|
6
|
-
|
7
|
-
import logging
|
9
|
+
|
8
10
|
logger = logging.getLogger("pycityagent")
|
9
11
|
|
12
|
+
|
10
13
|
def extract_json(output_str):
|
11
14
|
try:
|
12
15
|
# Find the positions of the first '{' and the last '}'
|
13
|
-
start = output_str.find(
|
14
|
-
end = output_str.rfind(
|
15
|
-
|
16
|
+
start = output_str.find("{")
|
17
|
+
end = output_str.rfind("}")
|
18
|
+
|
16
19
|
# Extract the substring containing the JSON
|
17
|
-
json_str = output_str[start:end+1]
|
18
|
-
|
20
|
+
json_str = output_str[start : end + 1]
|
21
|
+
|
19
22
|
# Convert the JSON string to a dictionary
|
20
23
|
return json_str
|
21
24
|
except (ValueError, json.JSONDecodeError) as e:
|
22
25
|
logger.warning(f"Failed to extract JSON: {e}")
|
23
26
|
return None
|
24
27
|
|
28
|
+
|
25
29
|
class CognitionBlock(Block):
|
26
30
|
configurable_fields = ["top_k"]
|
27
31
|
default_values = {"top_k": 20}
|
@@ -32,12 +36,12 @@ class CognitionBlock(Block):
|
|
32
36
|
def __init__(self, llm: LLM, memory: Memory, simulator: Simulator):
|
33
37
|
super().__init__("CognitionBlock", llm=llm, memory=memory, simulator=simulator)
|
34
38
|
self.top_k = 20
|
35
|
-
|
39
|
+
|
36
40
|
async def set_status(self, status):
|
37
41
|
for key in status:
|
38
42
|
await self.memory.status.update(key, status[key])
|
39
43
|
return
|
40
|
-
|
44
|
+
|
41
45
|
async def attitude_update(self):
|
42
46
|
"""Cognition - attitude update workflow"""
|
43
47
|
attitude = await self.memory.status.get("attitude")
|
@@ -56,7 +60,7 @@ class CognitionBlock(Block):
|
|
56
60
|
"income": await self.memory.status.get("income"),
|
57
61
|
"skill": await self.memory.status.get("skill"),
|
58
62
|
"thought": await self.memory.status.get("thought"),
|
59
|
-
"emotion_types": await self.memory.status.get("emotion_types")
|
63
|
+
"emotion_types": await self.memory.status.get("emotion_types"),
|
60
64
|
}
|
61
65
|
for topic in attitude:
|
62
66
|
description_prompt = """
|
@@ -82,7 +86,7 @@ class CognitionBlock(Block):
|
|
82
86
|
f"You need to decide your attitude towards topic: {topic}, "
|
83
87
|
f"which you previously rated your attitude towards this topic as: {previous_attitude} "
|
84
88
|
"(0 meaning oppose, 10 meaning support). "
|
85
|
-
|
89
|
+
'Please return a new attitude rating (0-10, smaller meaning oppose, larger meaning support) in JSON format, and explain, e.g. {{"attitude": 5}}'
|
86
90
|
)
|
87
91
|
question_prompt = description_prompt + incident_prompt + problem_prompt
|
88
92
|
question_prompt = FormatPrompt(question_prompt)
|
@@ -99,22 +103,25 @@ class CognitionBlock(Block):
|
|
99
103
|
prompt_data["disgust"] = disgust
|
100
104
|
prompt_data["anger"] = anger
|
101
105
|
prompt_data["surprise"] = surprise
|
102
|
-
|
106
|
+
|
103
107
|
question_prompt.format(**prompt_data)
|
104
108
|
evaluation = True
|
109
|
+
response: dict = {}
|
105
110
|
for retry in range(10):
|
106
111
|
try:
|
107
|
-
|
108
|
-
|
112
|
+
_response = await self.llm.atext_request(
|
113
|
+
question_prompt.to_dialog(), timeout=300
|
114
|
+
)
|
115
|
+
response = json.loads(extract_json(_response)) # type:ignore
|
109
116
|
evaluation = False
|
110
117
|
break
|
111
118
|
except:
|
112
119
|
pass
|
113
120
|
if evaluation:
|
114
|
-
raise f"Request for attitude:{topic} update failed"
|
121
|
+
raise Exception(f"Request for attitude:{topic} update failed")
|
115
122
|
attitude[topic] = response["attitude"]
|
116
123
|
await self.memory.status.update("attitude", attitude)
|
117
|
-
|
124
|
+
|
118
125
|
async def thought_update(self):
|
119
126
|
"""Cognition - thought update workflow"""
|
120
127
|
description_prompt = """
|
@@ -171,33 +178,36 @@ class CognitionBlock(Block):
|
|
171
178
|
surprise=surprise,
|
172
179
|
emotion=await self.memory.status.get("emotion"),
|
173
180
|
thought=await self.memory.status.get("thought"),
|
174
|
-
emotion_types=await self.memory.status.get("emotion_types")
|
181
|
+
emotion_types=await self.memory.status.get("emotion_types"),
|
175
182
|
)
|
176
|
-
|
183
|
+
|
177
184
|
evaluation = True
|
185
|
+
response: dict = {}
|
178
186
|
for retry in range(10):
|
179
187
|
try:
|
180
|
-
|
181
|
-
|
188
|
+
_response = await self.llm.atext_request(
|
189
|
+
question_prompt.to_dialog(), timeout=300
|
190
|
+
)
|
191
|
+
response = json.loads(extract_json(_response)) # type:ignore
|
182
192
|
evaluation = False
|
183
193
|
break
|
184
194
|
except:
|
185
195
|
pass
|
186
196
|
if evaluation:
|
187
197
|
raise Exception("Request for cognition update failed")
|
188
|
-
|
198
|
+
|
189
199
|
thought = str(response["thought"])
|
190
200
|
await self.memory.status.update("thought", thought)
|
191
201
|
await self.memory.stream.add_cognition(description=thought)
|
192
202
|
return
|
193
|
-
|
203
|
+
|
194
204
|
async def end_of_day(self):
|
195
205
|
"""Cognition - end of day workflow"""
|
196
206
|
time = await self.simulator.get_simulator_second_from_start_of_day()
|
197
207
|
if time >= 86400 - 10 * 60:
|
198
208
|
return True
|
199
209
|
return False
|
200
|
-
|
210
|
+
|
201
211
|
async def forward(self):
|
202
212
|
"""Cognition workflow: Daily update"""
|
203
213
|
# cognition update: thought and attitude
|
@@ -220,7 +230,7 @@ class CognitionBlock(Block):
|
|
220
230
|
Joy, Distress, Resentment, Pity, Hope, Fear, Satisfaction, Relief, Disappointment, Pride, Admiration, Shame, Reproach, Liking, Disliking, Gratitude, Anger, Gratification, Remorse, Love, Hate.
|
221
231
|
"""
|
222
232
|
|
223
|
-
incident_prompt = f"{incident}" #waiting for incident port
|
233
|
+
incident_prompt = f"{incident}" # waiting for incident port
|
224
234
|
question_prompt = """
|
225
235
|
Please reconsider your emotion intensities:
|
226
236
|
sadness, joy, fear, disgust, anger, surprise (0 meaning not at all, 10 meaning very much).
|
@@ -256,14 +266,17 @@ class CognitionBlock(Block):
|
|
256
266
|
surprise=surprise,
|
257
267
|
emotion=await self.memory.status.get("emotion"),
|
258
268
|
thought=await self.memory.status.get("thought"),
|
259
|
-
emotion_types=await self.memory.status.get("emotion_types")
|
269
|
+
emotion_types=await self.memory.status.get("emotion_types"),
|
260
270
|
)
|
261
|
-
|
271
|
+
|
262
272
|
evaluation = True
|
273
|
+
response: dict = {}
|
263
274
|
for retry in range(10):
|
264
275
|
try:
|
265
|
-
|
266
|
-
|
276
|
+
_response = await self.llm.atext_request(
|
277
|
+
question_prompt.to_dialog(), timeout=300
|
278
|
+
)
|
279
|
+
response = json.loads(extract_json(_response)) # type:ignore
|
267
280
|
evaluation = False
|
268
281
|
break
|
269
282
|
except Exception as e:
|
@@ -272,6 +285,16 @@ class CognitionBlock(Block):
|
|
272
285
|
if evaluation:
|
273
286
|
raise Exception("Request for cognition update failed")
|
274
287
|
|
275
|
-
await self.memory.status.update(
|
288
|
+
await self.memory.status.update(
|
289
|
+
"emotion",
|
290
|
+
{
|
291
|
+
"sadness": int(response["sadness"]),
|
292
|
+
"joy": int(response["joy"]),
|
293
|
+
"fear": int(response["fear"]),
|
294
|
+
"disgust": int(response["disgust"]),
|
295
|
+
"anger": int(response["anger"]),
|
296
|
+
"surprise": int(response["surprise"]),
|
297
|
+
},
|
298
|
+
)
|
276
299
|
await self.memory.status.update("emotion_types", str(response["word"]))
|
277
300
|
return response["conclusion"]
|
@@ -1,9 +1,11 @@
|
|
1
|
+
import logging
|
1
2
|
import random
|
2
3
|
from typing import Dict, List
|
4
|
+
|
3
5
|
from pycityagent.llm.llm import LLM
|
4
6
|
from pycityagent.workflow.block import Block
|
5
7
|
from pycityagent.workflow.prompt import FormatPrompt
|
6
|
-
|
8
|
+
|
7
9
|
logger = logging.getLogger("pycityagent")
|
8
10
|
|
9
11
|
DISPATCHER_PROMPT = """
|
@@ -14,18 +16,19 @@ Step information:
|
|
14
16
|
{step}
|
15
17
|
"""
|
16
18
|
|
19
|
+
|
17
20
|
class BlockDispatcher:
|
18
21
|
def __init__(self, llm: LLM):
|
19
22
|
self.llm = llm
|
20
23
|
self.blocks: Dict[str, Block] = {}
|
21
24
|
self.prompt = FormatPrompt(DISPATCHER_PROMPT)
|
22
|
-
|
25
|
+
|
23
26
|
def register_blocks(self, blocks: List[Block]) -> None:
|
24
27
|
"""Register multiple blocks at once"""
|
25
28
|
for block in blocks:
|
26
29
|
block_name = block.__class__.__name__.lower()
|
27
30
|
self.blocks[block_name] = block
|
28
|
-
|
31
|
+
|
29
32
|
def _get_function_schema(self) -> dict:
|
30
33
|
"""Generate function schema for LLM function call"""
|
31
34
|
# 创建 block 选项说明
|
@@ -33,7 +36,7 @@ class BlockDispatcher:
|
|
33
36
|
name: block.description # type: ignore
|
34
37
|
for name, block in self.blocks.items()
|
35
38
|
}
|
36
|
-
|
39
|
+
|
37
40
|
return {
|
38
41
|
"type": "function",
|
39
42
|
"function": {
|
@@ -45,34 +48,36 @@ class BlockDispatcher:
|
|
45
48
|
"block_name": {
|
46
49
|
"type": "string",
|
47
50
|
"enum": list(self.blocks.keys()),
|
48
|
-
"description": f"Available blocks and their descriptions: {block_descriptions}"
|
51
|
+
"description": f"Available blocks and their descriptions: {block_descriptions}",
|
49
52
|
}
|
50
53
|
},
|
51
|
-
"required": ["block_name"]
|
52
|
-
}
|
53
|
-
}
|
54
|
+
"required": ["block_name"],
|
55
|
+
},
|
56
|
+
},
|
54
57
|
}
|
55
|
-
|
58
|
+
|
56
59
|
async def dispatch(self, step: dict) -> Block:
|
57
60
|
"""Dispatch the step to appropriate block based on LLM function call"""
|
58
61
|
try:
|
59
62
|
function_schema = self._get_function_schema()
|
60
63
|
self.prompt.format(step=step)
|
61
|
-
|
64
|
+
|
62
65
|
# Call LLM with tools schema
|
63
66
|
function_args = await self.llm.atext_request(
|
64
67
|
self.prompt.to_dialog(),
|
65
68
|
tools=[function_schema],
|
66
|
-
tool_choice={"type": "function", "function": {"name": "select_block"}}
|
69
|
+
tool_choice={"type": "function", "function": {"name": "select_block"}},
|
67
70
|
)
|
68
|
-
|
69
|
-
selected_block = function_args.get("block_name")
|
70
|
-
|
71
|
+
|
72
|
+
selected_block = function_args.get("block_name") # type: ignore
|
73
|
+
|
71
74
|
if selected_block not in self.blocks:
|
72
|
-
raise ValueError(
|
73
|
-
|
75
|
+
raise ValueError(
|
76
|
+
f"Selected block '{selected_block}' not found in registered blocks"
|
77
|
+
)
|
78
|
+
|
74
79
|
return self.blocks[selected_block]
|
75
|
-
|
80
|
+
|
76
81
|
except Exception as e:
|
77
82
|
logger.warning(f"Failed to dispatch block: {e}")
|
78
83
|
return random.choice(list(self.blocks.values()))
|
@@ -3,6 +3,7 @@ import random
|
|
3
3
|
from pycityagent.llm.llm import LLM
|
4
4
|
from pycityagent.workflow.block import Block
|
5
5
|
from pycityagent.memory import Memory
|
6
|
+
import pycityproto.city.economy.v2.economy_pb2 as economyv2
|
6
7
|
|
7
8
|
from .utils import clean_json_response, TIME_ESTIMATE_PROMPT
|
8
9
|
|
@@ -21,6 +22,15 @@ from pycityagent.workflow import Block
|
|
21
22
|
from pycityagent.economy import EconomyClient
|
22
23
|
from .utils import *
|
23
24
|
import numbers
|
25
|
+
import numpy as np
|
26
|
+
import asyncio
|
27
|
+
|
28
|
+
def softmax(x, gamma=1.0):
|
29
|
+
if not isinstance(x, np.ndarray):
|
30
|
+
x = np.array(x)
|
31
|
+
x *= gamma
|
32
|
+
e_x = np.exp(x - np.max(x))
|
33
|
+
return e_x / e_x.sum(axis=-1, keepdims=True)
|
24
34
|
|
25
35
|
class WorkBlock(Block):
|
26
36
|
"""WorkPlace Block"""
|
@@ -80,10 +90,10 @@ class ConsumptionBlock(Block):
|
|
80
90
|
async def forward(self, step, context):
|
81
91
|
self.forward_times += 1
|
82
92
|
agent_id = await self.memory.status.get("id") # agent_id
|
83
|
-
|
93
|
+
firms_id = await self.economy_client.get_org_entity_ids(economyv2.ORG_TYPE_FIRM)
|
84
94
|
intention = step["intention"]
|
85
95
|
month_consumption = await self.memory.status.get('to_consumption_currency')
|
86
|
-
consumption_currency = await self.
|
96
|
+
consumption_currency = await self.economy_client.get(agent_id, 'consumption')
|
87
97
|
if consumption_currency >= month_consumption:
|
88
98
|
node_id = await self.memory.stream.add_economy(description=f"I have passed the monthly consumption limit, so I will not consume.")
|
89
99
|
return {
|
@@ -93,20 +103,20 @@ class ConsumptionBlock(Block):
|
|
93
103
|
'node_id': node_id
|
94
104
|
}
|
95
105
|
consumption = min(month_consumption/1, month_consumption-consumption_currency)
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
await self.
|
106
|
-
node_id = await self.memory.stream.add_economy(description=f"I bought some goods, and spent {
|
106
|
+
prices = []
|
107
|
+
for firm_id in firms_id:
|
108
|
+
price = await self.economy_client.get(firm_id, 'price')
|
109
|
+
prices.append(price)
|
110
|
+
consumption_each_firm = consumption*softmax(prices, gamma=-0.01)
|
111
|
+
demand_each_firm = []
|
112
|
+
for i in range(len(firms_id)):
|
113
|
+
demand_each_firm.append(int(consumption_each_firm//prices[i]))
|
114
|
+
|
115
|
+
real_consumption = await self.economy_client.calculate_consumption(firms_id, agent_id, demand_each_firm)
|
116
|
+
node_id = await self.memory.stream.add_economy(description=f"I bought some goods, and spent {real_consumption:.1f} on {intention}")
|
107
117
|
evaluation = {
|
108
118
|
'success': True,
|
109
|
-
'evaluation': f"I bought some goods, and spent {
|
119
|
+
'evaluation': f"I bought some goods, and spent {real_consumption:.1f} on {intention}",
|
110
120
|
'consumed_time': 20,
|
111
121
|
'node_id': node_id
|
112
122
|
}
|
@@ -172,16 +182,22 @@ class MonthPlanBlock(Block):
|
|
172
182
|
async def forward(self):
|
173
183
|
if await self.month_trigger():
|
174
184
|
agent_id = await self.memory.status.get("id")
|
185
|
+
firms_id = await self.economy_client.get_org_entity_ids(economyv2.ORG_TYPE_FIRM)
|
175
186
|
firm_id = await self.memory.status.get('firm_id')
|
176
|
-
bank_id = await self.
|
187
|
+
bank_id = await self.economy_client.get_org_entity_ids(economyv2.ORG_TYPE_BANK)
|
188
|
+
bank_id = bank_id[0]
|
177
189
|
name = await self.memory.status.get('name')
|
178
190
|
age = await self.memory.status.get('age')
|
179
191
|
city = await self.memory.status.get('city')
|
180
192
|
job = await self.memory.status.get('occupation')
|
181
|
-
skill = await self.
|
182
|
-
consumption = await self.
|
193
|
+
skill = await self.economy_client.get(agent_id, 'skill')
|
194
|
+
consumption = await self.economy_client.get(agent_id, 'consumption')
|
183
195
|
tax_paid = await self.memory.status.get('tax_paid')
|
184
|
-
|
196
|
+
prices = []
|
197
|
+
for firm_id in firms_id:
|
198
|
+
price = await self.economy_client.get(firm_id, 'price')
|
199
|
+
prices.append(price)
|
200
|
+
price = np.mean(prices)
|
185
201
|
wealth = await self.economy_client.get(agent_id, 'currency')
|
186
202
|
interest_rate = await self.economy_client.get(bank_id, 'interest_rate')
|
187
203
|
|
@@ -232,27 +248,27 @@ class MonthPlanBlock(Block):
|
|
232
248
|
except:
|
233
249
|
self.llm_error += 1
|
234
250
|
|
235
|
-
|
251
|
+
work_skill = await self.economy_client.get(agent_id, 'skill')
|
236
252
|
work_propensity = await self.memory.status.get('work_propensity')
|
237
253
|
consumption_propensity = await self.memory.status.get('consumption_propensity')
|
238
254
|
work_hours = work_propensity * num_labor_hours
|
239
|
-
await self.
|
255
|
+
income = await self.economy_client.get(agent_id, 'income')
|
256
|
+
income += work_hours * work_skill
|
257
|
+
|
240
258
|
wealth = await self.economy_client.get(agent_id, 'currency')
|
241
|
-
|
259
|
+
wealth += work_hours * work_skill
|
260
|
+
await self.economy_client.update(agent_id, 'currency', wealth)
|
242
261
|
await self.economy_client.add_delta_value(firm_id, 'inventory', int(work_hours*productivity_per_labor))
|
243
262
|
|
244
263
|
if UBI and self.forward_times >= 96:
|
245
|
-
|
246
|
-
|
247
|
-
wealth = await self.economy_client.get(agent_id, 'currency')
|
248
|
-
await self.economy_client.update(agent_id, 'currency', wealth + UBI)
|
264
|
+
income += UBI
|
265
|
+
wealth += UBI
|
249
266
|
|
250
|
-
wealth = await self.economy_client.get(agent_id, 'currency')
|
251
267
|
await self.memory.status.update('to_consumption_currency', consumption_propensity*wealth)
|
252
268
|
|
253
|
-
await self.
|
254
|
-
await self.
|
255
|
-
await self.
|
269
|
+
await self.economy_client.update(agent_id, 'consumption', 0)
|
270
|
+
await self.economy_client.update(agent_id, 'income', income)
|
271
|
+
await self.economy_client.update(agent_id, 'currency', wealth)
|
256
272
|
|
257
273
|
if self.forward_times % 3 == 0:
|
258
274
|
obs_prompt = f'''
|
@@ -312,6 +328,4 @@ class MonthPlanBlock(Block):
|
|
312
328
|
obs_prompt = prettify_document(obs_prompt)
|
313
329
|
content = await self.llm.atext_request([{'role': 'user', 'content': obs_prompt}], timeout=300)
|
314
330
|
await self.memory.status.update('ubi_opinion', [content], mode='merge')
|
315
|
-
|
316
|
-
self.forward_times += 1
|
317
|
-
await self.memory.status.update('forward', self.forward_times)
|
331
|
+
|