++
This commit is contained in:
@@ -11,7 +11,29 @@ from app.constants import TIMES_OF_DAY, normalize_emotional_state
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ActionResolver:
|
||||
class ActionResolver:
|
||||
@staticmethod
|
||||
def _resolve_resource_name(raw_name, available: set[str]) -> str | None:
|
||||
"""Return a valid resource key or None for an LLM-invented key.
|
||||
|
||||
Action arguments are generated text, so a model may describe a
|
||||
resource (for example, "my own labor and what scraps I have") instead
|
||||
of using one of the machine-readable keys in the world blueprint.
|
||||
Resource mutations must never use that unchecked value as a dict key.
|
||||
"""
|
||||
if not isinstance(raw_name, str):
|
||||
return None
|
||||
value = raw_name.strip()
|
||||
if not value:
|
||||
return None
|
||||
if value in available:
|
||||
return value
|
||||
lowered = value.lower()
|
||||
for resource in available:
|
||||
if str(resource).lower() == lowered:
|
||||
return resource
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def _resolve_agent_id(ref, agent_map: dict[int, AgentPersona]) -> int | None:
|
||||
if ref is None:
|
||||
@@ -351,15 +373,33 @@ class ActionResolver:
|
||||
self._strengthen_social_edge(other, agent.id, 0.05, 0.1)
|
||||
rel_changes[str(other.id)] = "impressed"
|
||||
|
||||
elif at == ActionType.BUILD:
|
||||
cost_resource = action_args.get("resource", "goods")
|
||||
try:
|
||||
cost_amount = int(action_args.get("cost", 20))
|
||||
except (ValueError, TypeError):
|
||||
cost_amount = 20
|
||||
if agent.resources.get(cost_resource, 0) >= cost_amount:
|
||||
agent.resources[cost_resource] -= cost_amount
|
||||
world_changes["built"] = action_args.get("what", "something")
|
||||
elif at == ActionType.BUILD:
|
||||
# Only blueprint resources are valid action keys. Persona data
|
||||
# can also contain arbitrary model-generated labels, so accepting
|
||||
# every key currently present in ``agent.resources`` would let an
|
||||
# invented phrase become part of the simulation vocabulary.
|
||||
available_resources = {
|
||||
str(resource) for resource in world_state.blueprint.resources
|
||||
}
|
||||
raw_resource = action_args.get("resource", "goods")
|
||||
cost_resource = self._resolve_resource_name(raw_resource, available_resources)
|
||||
try:
|
||||
cost_amount = int(action_args.get("cost", 20))
|
||||
except (ValueError, TypeError):
|
||||
cost_amount = 20
|
||||
if cost_amount <= 0:
|
||||
cost_amount = 20
|
||||
|
||||
if cost_resource is None:
|
||||
logger.warning(
|
||||
"居民 %s 的 BUILD 行动使用了无效资源 %r,已忽略该行动",
|
||||
agent.name,
|
||||
raw_resource,
|
||||
)
|
||||
world_changes["build_failed"] = "invalid_resource"
|
||||
elif agent.resources.get(cost_resource, 0) >= cost_amount:
|
||||
agent.resources[cost_resource] -= cost_amount
|
||||
world_changes["built"] = action_args.get("what", "something")
|
||||
|
||||
elif at == ActionType.OBSERVE:
|
||||
agent.resources["knowledge"] = agent.resources.get("knowledge", 0) + 3
|
||||
|
||||
Reference in New Issue
Block a user