WorldSmithAI / behaviors /governance.py
Srishti280992's picture
Upload 39 files
caad8d0 verified
Raw History Blame
64.2 kB
"""
Generic governance behaviors for WorldSmithAI.
This module implements domain-agnostic governance behaviors for arbitrary
agent-based worlds. It deliberately avoids domain-specific classes such as
Government, Court, Law, Permit, Judge, TaxOffice, Regulator, or Police.
Governance is represented through generic records stored in agent state and
memory. This allows DSL-generated worlds to model institutions, rules,
approvals, incentives, disputes, and enforcement without requiring Python code
changes.
Implemented behaviors:
- regulate: create or update generic regulation records.
- tax: collect numeric value from selected agents.
- subsidize: transfer or mint numeric support for selected agents.
- litigate: create and optionally resolve generic dispute records.
- approve: create approval, permit, authorization, or denial records.
- enforce: check compliance and apply penalties or state updates.
Example:
behavior = RegulateBehavior(
regulation_type="market_rule",
constraints={"state.inventory.food": {"min": 2}},
penalties={"credits": 1.0},
)
outcome = behavior.execute(agent, world)
behavior = TaxBehavior(
target_types=("merchant",),
tax_rate=0.1,
tax_base_key="credits",
source_account_key="credits",
recipient_account_key="treasury",
)
outcome = behavior.execute(agent, world)
Future extensibility:
- Add world-level governance registries.
- Add multi-agent voting and quorum rules.
- Add appeal processes and procedural histories.
- Add reputation-aware enforcement.
- Add smart-contract-like obligations.
- Add event emission for rules, violations, approvals, cases, and sanctions.
"""
from __future__ import annotations
import copy
import logging
from collections.abc import Iterable, Mapping, MutableMapping, MutableSequence, Sequence
from dataclasses import dataclass, field
from enum import Enum
from numbers import Real
from types import MappingProxyType
from typing import TYPE_CHECKING, Any, ClassVar
import numpy as np
from core.behavior import Behavior
if TYPE_CHECKING:
from core.agent import Agent
from core.world import World
logger = logging.getLogger(__name__)
_MISSING = object()
class StorageLocation(str, Enum):
"""Supported mutable storage locations on an agent."""
STATE = "state"
MEMORY = "memory"
class CaseStatus(str, Enum):
"""Generic statuses for litigation or dispute records."""
FILED = "filed"
CLAIMANT_PREVAILS = "claimant_prevails"
RESPONDENT_PREVAILS = "respondent_prevails"
DISMISSED = "dismissed"
SETTLED = "settled"
class ApprovalStatus(str, Enum):
"""Generic statuses for approval records."""
APPROVED = "approved"
DENIED = "denied"
REVOKED = "revoked"
@dataclass(frozen=True)
class GovernanceOutcome:
"""Serializable result returned by governance behavior execution.
The core engine may ignore this object, but downstream systems such as
metrics, visualizers, audit logs, event streams, and narrators can consume
the structured payload.
"""
behavior: str
actor_id: str
success: bool
target_ids: tuple[str, ...] = ()
record_ids: tuple[str, ...] = ()
step: int | None = None
details: Mapping[str, Any] = field(default_factory=dict)
def to_dict(self) -> dict[str, Any]:
"""Return a JSON-friendly representation of the outcome."""
return {
"behavior": self.behavior,
"actor_id": self.actor_id,
"success": self.success,
"target_ids": list(self.target_ids),
"record_ids": list(self.record_ids),
"step": self.step,
"details": copy.deepcopy(dict(self.details)),
}
def _agent_id(agent: Agent) -> str:
"""Return a stable string identifier for an agent."""
return str(getattr(agent, "id"))
def _agent_type(agent: Agent) -> str:
"""Return the generic type label for an agent."""
return str(getattr(agent, "type", ""))
def _is_alive(agent: Agent) -> bool:
"""Return whether an agent can participate in behavior execution."""
return bool(getattr(agent, "alive", True))
def _world_step(world: World) -> int | None:
"""Return the current simulation step if available."""
value = getattr(world, "step_count", None)
if isinstance(value, Real) and not isinstance(value, bool):
return int(value)
return None
def _is_number(value: Any) -> bool:
"""Return whether a value is a real numeric scalar, excluding booleans."""
return isinstance(value, (Real, np.integer, np.floating)) and not isinstance(value, bool)
def _as_float(value: Any, default: float = 0.0) -> float:
"""Safely convert a numeric-like value to float."""
if _is_number(value):
return float(value)
return default
def _as_int(value: Any, default: int = 0) -> int:
"""Safely convert a numeric-like value to int."""
if _is_number(value):
return int(value)
return default
def _normalize_storage(location: StorageLocation | str) -> StorageLocation:
"""Normalize a storage location value."""
if isinstance(location, StorageLocation):
return location
return StorageLocation(str(location))
def _agent_state(agent: Agent) -> MutableMapping[str, Any]:
"""Return an agent's mutable state mapping, creating one if needed."""
state = getattr(agent, "state", None)
if isinstance(state, MutableMapping):
return state
replacement: dict[str, Any] = {}
setattr(agent, "state", replacement)
return replacement
def _agent_memory(agent: Agent) -> MutableMapping[str, Any]:
"""Return an agent's mutable memory mapping, creating one if needed."""
memory = getattr(agent, "memory", None)
if isinstance(memory, MutableMapping):
return memory
replacement: dict[str, Any] = {}
setattr(agent, "memory", replacement)
return replacement
def _container_for(agent: Agent, location: StorageLocation | str) -> MutableMapping[str, Any]:
"""Return an agent container for a state-or-memory storage location."""
normalized = _normalize_storage(location)
if normalized is StorageLocation.STATE:
return _agent_state(agent)
if normalized is StorageLocation.MEMORY:
return _agent_memory(agent)
raise ValueError(f"Unsupported storage location: {location!r}")
def _ensure_mapping(parent: MutableMapping[str, Any], key: str) -> MutableMapping[str, Any]:
"""Return a nested mutable mapping under ``key``, creating one if absent."""
value = parent.get(key)
if isinstance(value, MutableMapping):
return value
if isinstance(value, Mapping):
replacement = dict(value)
parent[key] = replacement
return replacement
replacement: dict[str, Any] = {}
parent[key] = replacement
return replacement
def _ensure_list(parent: MutableMapping[str, Any], key: str) -> MutableSequence[Any]:
"""Return a nested mutable sequence under ``key``, creating one if absent."""
value = parent.get(key)
if isinstance(value, MutableSequence):
return value
replacement: list[Any] = []
parent[key] = replacement
return replacement
def _append_bounded(items: MutableSequence[Any], value: Any, max_items: int) -> None:
"""Append an item while enforcing an optional maximum history length."""
items.append(value)
if max_items > 0 and len(items) > max_items:
del items[: len(items) - max_items]
def _split_path(path: str) -> tuple[str, ...]:
"""Split a dot-separated path into components."""
return tuple(part for part in str(path).split(".") if part)
def _get_path(container: Mapping[str, Any], path: str, default: Any = None) -> Any:
"""Read a possibly nested value from a mapping using dot notation."""
parts = _split_path(path)
if not parts:
return default
current: Any = container
for part in parts:
if not isinstance(current, Mapping) or part not in current:
return default
current = current[part]
return current
def _set_path(container: MutableMapping[str, Any], path: str, value: Any) -> None:
"""Write a possibly nested value to a mapping using dot notation."""
parts = _split_path(path)
if not parts:
return
current: MutableMapping[str, Any] = container
for part in parts[:-1]:
nested = current.get(part)
if not isinstance(nested, MutableMapping):
nested = {}
current[part] = nested
current = nested
current[parts[-1]] = value
def _increment_path(container: MutableMapping[str, Any], path: str, delta: float) -> float:
"""Increment a numeric value at a path and return the updated value."""
current_value = _get_path(container, path, 0.0)
updated_value = _as_float(current_value, 0.0) + float(delta)
_set_path(container, path, updated_value)
return updated_value
def _delete_path(container: MutableMapping[str, Any], path: str) -> None:
"""Delete a possibly nested value from a mapping using dot notation."""
parts = _split_path(path)
if not parts:
return
current: MutableMapping[str, Any] = container
for part in parts[:-1]:
nested = current.get(part)
if not isinstance(nested, MutableMapping):
return
current = nested
current.pop(parts[-1], None)
def _iter_world_agents(world: World) -> tuple[Agent, ...]:
"""Return all agent-like objects from a world."""
agents = getattr(world, "agents", ())
if isinstance(agents, Mapping):
raw_agents: Iterable[Any] = agents.values()
elif isinstance(agents, Iterable) and not isinstance(agents, (str, bytes)):
raw_agents = agents
else:
raw_agents = ()
return tuple(agent for agent in raw_agents if hasattr(agent, "id"))
def _find_agent(world: World, agent_id: str | None) -> Agent | None:
"""Find an agent by id."""
if agent_id is None:
return None
expected_id = str(agent_id)
for candidate in _iter_world_agents(world):
if _agent_id(candidate) == expected_id:
return candidate
return None
def _select_targets(
agent: Agent,
world: World,
*,
target_agent_id: str | None,
target_types: Sequence[str],
max_targets: int,
include_self: bool = False,
) -> tuple[Agent, ...]:
"""Select alive targets deterministically by explicit id, type, and id order."""
if max_targets <= 0:
return ()
if target_agent_id is not None:
target = _find_agent(world, target_agent_id)
if target is None or not _is_alive(target):
return ()
if not include_self and _agent_id(target) == _agent_id(agent):
return ()
return (target,)
allowed_types = {str(target_type) for target_type in target_types}
candidates: list[Agent] = []
for candidate in _iter_world_agents(world):
if not include_self and _agent_id(candidate) == _agent_id(agent):
continue
if not _is_alive(candidate):
continue
if allowed_types and _agent_type(candidate) not in allowed_types:
continue
candidates.append(candidate)
return tuple(sorted(candidates, key=_agent_id)[:max_targets])
def _read_agent_value(agent: Agent, path: str, default: Any = _MISSING) -> Any:
"""Read an agent value using optional state or memory prefixes.
Supported prefixes:
- ``state.foo.bar``
- ``state:foo.bar``
- ``memory.foo.bar``
- ``memory:foo.bar``
If no prefix is supplied, state is checked first, then memory.
"""
normalized_path = str(path)
if normalized_path.startswith("state."):
return _get_path(_agent_state(agent), normalized_path.removeprefix("state."), default)
if normalized_path.startswith("state:"):
return _get_path(_agent_state(agent), normalized_path.removeprefix("state:"), default)
if normalized_path.startswith("memory."):
return _get_path(_agent_memory(agent), normalized_path.removeprefix("memory."), default)
if normalized_path.startswith("memory:"):
return _get_path(_agent_memory(agent), normalized_path.removeprefix("memory:"), default)
state_value = _get_path(_agent_state(agent), normalized_path, _MISSING)
if state_value is not _MISSING:
return state_value
return _get_path(_agent_memory(agent), normalized_path, default)
def _write_agent_value(
agent: Agent,
path: str,
value: Any,
*,
default_location: StorageLocation | str = StorageLocation.STATE,
) -> None:
"""Write an agent value using optional state or memory prefixes."""
normalized_path = str(path)
if normalized_path.startswith("state."):
_set_path(_agent_state(agent), normalized_path.removeprefix("state."), value)
return
if normalized_path.startswith("state:"):
_set_path(_agent_state(agent), normalized_path.removeprefix("state:"), value)
return
if normalized_path.startswith("memory."):
_set_path(_agent_memory(agent), normalized_path.removeprefix("memory."), value)
return
if normalized_path.startswith("memory:"):
_set_path(_agent_memory(agent), normalized_path.removeprefix("memory:"), value)
return
_set_path(_container_for(agent, default_location), normalized_path, value)
def _increment_agent_value(
agent: Agent,
path: str,
delta: float,
*,
default_location: StorageLocation | str = StorageLocation.STATE,
) -> float:
"""Increment an agent value using optional state or memory prefixes."""
current_value = _read_agent_value(agent, path, 0.0)
updated_value = _as_float(current_value, 0.0) + float(delta)
_write_agent_value(agent, path, updated_value, default_location=default_location)
return updated_value
def _safe_equal(left: Any, right: Any) -> bool:
"""Return safe equality for arbitrary DSL values."""
try:
result = left == right
except (TypeError, ValueError):
return False
if isinstance(result, np.ndarray):
return bool(result.all())
return bool(result)
def _constraint_matches(actual: Any, expected: Any) -> bool:
"""Return whether a value satisfies a generic DSL constraint."""
if isinstance(expected, Mapping):
exists = expected.get("exists")
if exists is not None:
has_value = actual is not _MISSING and actual is not None
if bool(exists) != has_value:
return False
if actual is _MISSING:
return False
if "equals" in expected and not _safe_equal(actual, expected["equals"]):
return False
if "not_equals" in expected and _safe_equal(actual, expected["not_equals"]):
return False
if "min" in expected:
if not _is_number(actual) or float(actual) < float(expected["min"]):
return False
if "max" in expected:
if not _is_number(actual) or float(actual) > float(expected["max"]):
return False
if "in" in expected:
valid_values = expected["in"]
if not isinstance(valid_values, Iterable) or isinstance(valid_values, (str, bytes)):
return False
if actual not in valid_values:
return False
if "not_in" in expected:
invalid_values = expected["not_in"]
if isinstance(invalid_values, Iterable) and not isinstance(invalid_values, (str, bytes)):
if actual in invalid_values:
return False
if "contains" in expected:
contained_value = expected["contains"]
if isinstance(actual, Mapping):
if contained_value not in actual:
return False
elif isinstance(actual, Iterable) and not isinstance(actual, (str, bytes)):
if contained_value not in actual:
return False
else:
return False
return True
if actual is _MISSING:
return False
return _safe_equal(actual, expected)
def _matches_constraints(agent: Agent, constraints: Mapping[str, Any]) -> bool:
"""Return whether an agent satisfies all generic path constraints."""
for path, expected in constraints.items():
actual = _read_agent_value(agent, str(path), _MISSING)
if not _constraint_matches(actual, expected):
return False
return True
def _has_authority(
agent: Agent,
*,
authority_key: str,
required_authority: float,
) -> bool:
"""Return whether an agent has enough generic authority to act."""
if required_authority <= 0:
return True
authority_value = _read_agent_value(agent, authority_key, 0.0)
return _as_float(authority_value, 0.0) >= float(required_authority)
def _record_store(
agent: Agent,
*,
location: StorageLocation | str,
store_key: str,
) -> MutableMapping[str, Any]:
"""Return a mutable record store from state or memory."""
container = _container_for(agent, location)
existing = _get_path(container, store_key)
if isinstance(existing, MutableMapping):
return existing
if isinstance(existing, Mapping):
replacement = dict(existing)
_set_path(container, store_key, replacement)
return replacement
replacement: dict[str, Any] = {}
_set_path(container, store_key, replacement)
return replacement
def _generated_record_id(
agent: Agent,
*,
behavior: str,
category: str,
store: Mapping[str, Any],
step: int | None,
suffix: str | None = None,
) -> str:
"""Generate a deterministic governance record id."""
step_label = "unknown_step" if step is None else str(step)
suffix_label = "" if suffix is None else f":{suffix}"
return f"{step_label}:{_agent_id(agent)}:{behavior}:{category}:{len(store)}{suffix_label}"
def _record_history(
agent: Agent,
*,
history_key: str,
record: Mapping[str, Any],
max_history: int,
) -> None:
"""Append a bounded governance history record to agent memory."""
history = _ensure_list(_agent_memory(agent), history_key)
_append_bounded(history, copy.deepcopy(dict(record)), max_history)
def _numeric_balance(
agent: Agent,
*,
account_key: str,
location: StorageLocation | str,
) -> float:
"""Read a numeric account balance from an agent."""
container = _container_for(agent, location)
return _as_float(_get_path(container, account_key), 0.0)
def _change_numeric_balance(
agent: Agent,
*,
account_key: str,
location: StorageLocation | str,
delta: float,
) -> float:
"""Increment a numeric account balance and return the updated value."""
container = _container_for(agent, location)
return _increment_path(container, account_key, float(delta))
def _transfer_numeric(
source: Agent,
recipient: Agent,
*,
source_account_key: str,
recipient_account_key: str,
amount: float,
source_location: StorageLocation | str,
recipient_location: StorageLocation | str,
allow_partial: bool,
) -> float:
"""Transfer numeric value between two agent accounts."""
requested = max(0.0, float(amount))
if requested <= 0:
return 0.0
available = _numeric_balance(
source,
account_key=source_account_key,
location=source_location,
)
if not allow_partial and available < requested:
return 0.0
actual = min(available, requested)
if actual <= 0:
return 0.0
_change_numeric_balance(
source,
account_key=source_account_key,
location=source_location,
delta=-actual,
)
_change_numeric_balance(
recipient,
account_key=recipient_account_key,
location=recipient_location,
delta=actual,
)
return actual
def _mint_numeric(
recipient: Agent,
*,
account_key: str,
location: StorageLocation | str,
amount: float,
) -> float:
"""Create numeric value directly in a recipient account."""
actual = max(0.0, float(amount))
if actual <= 0:
return 0.0
_change_numeric_balance(
recipient,
account_key=account_key,
location=location,
delta=actual,
)
return actual
def _find_regulation_record(
enforcer: Agent,
target: Agent,
*,
regulation_id: str | None,
location: StorageLocation | str,
regulations_key: str,
) -> Mapping[str, Any] | None:
"""Find a regulation record on the target first, then on the enforcer."""
if regulation_id is None:
return None
for owner in (target, enforcer):
store = _record_store(owner, location=location, store_key=regulations_key)
record = store.get(regulation_id)
if isinstance(record, Mapping):
return record
return None
def _regulation_is_active(record: Mapping[str, Any], step: int | None) -> bool:
"""Return whether a regulation record is active at the current step."""
if not bool(record.get("active", True)):
return False
expires_step = record.get("expires_step")
if step is None or expires_step is None:
return True
if _is_number(expires_step):
return step <= int(expires_step)
return True
def _normalize_penalties(
penalties: Mapping[str, Any],
*,
default_account_key: str,
) -> dict[str, float]:
"""Normalize penalty records into account-path-to-amount mappings."""
normalized: dict[str, float] = {}
for key, value in penalties.items():
if not _is_number(value):
continue
amount = max(0.0, float(value))
if amount <= 0:
continue
normalized_key = default_account_key if str(key) in {"fine", "amount", "penalty"} else str(key)
normalized[normalized_key] = normalized.get(normalized_key, 0.0) + amount
return normalized
def _apply_updates(
agent: Agent,
updates: Mapping[str, Any],
*,
default_location: StorageLocation | str,
) -> dict[str, Any]:
"""Apply generic state or memory updates to an agent."""
applied: dict[str, Any] = {}
for path, value in updates.items():
copied_value = copy.deepcopy(value)
_write_agent_value(agent, str(path), copied_value, default_location=default_location)
applied[str(path)] = copied_value
return applied
def _success(
behavior: str,
agent: Agent,
*,
target_ids: Sequence[str] = (),
record_ids: Sequence[str] = (),
details: Mapping[str, Any] | None = None,
world: World | None = None,
) -> dict[str, Any]:
"""Build a successful behavior outcome dictionary."""
return GovernanceOutcome(
behavior=behavior,
actor_id=_agent_id(agent),
success=True,
target_ids=tuple(str(target_id) for target_id in target_ids),
record_ids=tuple(str(record_id) for record_id in record_ids),
step=_world_step(world) if world is not None else None,
details=details or {},
).to_dict()
def _failure(
behavior: str,
agent: Agent,
reason: str,
*,
details: Mapping[str, Any] | None = None,
world: World | None = None,
) -> dict[str, Any]:
"""Build a failed behavior outcome dictionary."""
payload: dict[str, Any] = {"reason": reason}
if details:
payload.update(details)
logger.debug("Behavior %s failed for agent %s: %s", behavior, _agent_id(agent), reason)
return GovernanceOutcome(
behavior=behavior,
actor_id=_agent_id(agent),
success=False,
step=_world_step(world) if world is not None else None,
details=payload,
).to_dict()
@dataclass
class RegulateBehavior(Behavior):
"""Create or update generic regulation records.
A regulation is a plain record. It can represent law, policy, treaty,
platform rule, lab protocol, traffic rule, trade constraint, magical oath,
resource quota, safety standard, or any other DSL-defined rule.
"""
name: ClassVar[str] = "regulate"
regulation_id: str | None = None
regulation_type: str = "rule"
target_agent_id: str | None = None
target_types: tuple[str, ...] = ()
max_targets: int = 1000
regulations_location: StorageLocation | str = StorageLocation.MEMORY
regulations_key: str = "regulations"
constraints: Mapping[str, Any] = field(default_factory=dict)
effects: Mapping[str, Any] = field(default_factory=dict)
penalties: Mapping[str, float] = field(default_factory=dict)
metadata: Mapping[str, Any] = field(default_factory=dict)
priority: float = 0.0
active: bool = True
duration_steps: int | None = None
overwrite_existing: bool = True
authority_key: str = "authority"
required_authority: float = 0.0
history_memory_key: str = "governance_history"
max_history: int = 500
def check_preconditions(self, agent: Agent, world: World) -> bool:
"""Return whether the agent can issue this regulation."""
if not _is_alive(agent) or not self.regulation_type:
return False
if not _has_authority(
agent,
authority_key=self.authority_key,
required_authority=self.required_authority,
):
return False
return bool(self._targets(agent, world))
def execute(self, agent: Agent, world: World) -> dict[str, Any]:
"""Create or update regulation records for selected targets."""
if not self.check_preconditions(agent, world):
return _failure(self.name, agent, "preconditions_not_met", world=world)
step = _world_step(world)
targets = self._targets(agent, world)
record_ids: list[str] = []
skipped_targets: list[str] = []
for target in targets:
store = _record_store(
target,
location=self.regulations_location,
store_key=self.regulations_key,
)
record_id = self.regulation_id or _generated_record_id(
agent,
behavior=self.name,
category=self.regulation_type,
store=store,
step=step,
suffix=_agent_id(target),
)
existing = store.get(record_id)
if existing is not None and not self.overwrite_existing:
skipped_targets.append(_agent_id(target))
continue
revision = 1
created_step = step
if isinstance(existing, Mapping):
revision = _as_int(existing.get("revision"), 0) + 1
created_step = existing.get("created_step", step)
record = {
"id": record_id,
"type": self.regulation_type,
"issued_by": _agent_id(agent),
"target_id": _agent_id(target),
"constraints": copy.deepcopy(dict(self.constraints)),
"effects": copy.deepcopy(dict(self.effects)),
"penalties": copy.deepcopy(dict(self.penalties)),
"metadata": copy.deepcopy(dict(self.metadata)),
"priority": float(self.priority),
"active": bool(self.active),
"revision": revision,
"created_step": created_step,
"updated_step": step,
"expires_step": None
if self.duration_steps is None or step is None
else step + int(self.duration_steps),
}
store[record_id] = record
record_ids.append(record_id)
history_record = {
"behavior": self.name,
"record_id": record_id,
"target_id": _agent_id(target),
"regulation_type": self.regulation_type,
"revision": revision,
"step": step,
}
_record_history(
agent,
history_key=self.history_memory_key,
record=history_record,
max_history=self.max_history,
)
if _agent_id(agent) != _agent_id(target):
_record_history(
target,
history_key=self.history_memory_key,
record=history_record,
max_history=self.max_history,
)
if not record_ids:
return _failure(
self.name,
agent,
"no_regulations_written",
details={"skipped_targets": skipped_targets},
world=world,
)
logger.debug(
"Agent %s issued %s regulation record(s)",
_agent_id(agent),
len(record_ids),
)
return _success(
self.name,
agent,
target_ids=tuple(_agent_id(target) for target in targets),
record_ids=tuple(record_ids),
details={
"regulation_type": self.regulation_type,
"records_written": len(record_ids),
"skipped_targets": skipped_targets,
},
world=world,
)
def _targets(self, agent: Agent, world: World) -> tuple[Agent, ...]:
"""Return the agents receiving the regulation record."""
if self.target_agent_id is None and not self.target_types:
return (agent,)
return _select_targets(
agent,
world,
target_agent_id=self.target_agent_id,
target_types=self.target_types,
max_targets=self.max_targets,
include_self=True,
)
@dataclass
class TaxBehavior(Behavior):
"""Collect generic numeric value from selected agents.
This behavior can represent taxes, dues, rent, platform fees, tariffs,
tribute, tolls, membership fees, carbon prices, research overhead, or any
other governance-driven extraction.
"""
name: ClassVar[str] = "tax"
target_agent_id: str | None = None
target_types: tuple[str, ...] = ()
max_targets: int = 1000
collector_agent_id: str | None = None
source_location: StorageLocation | str = StorageLocation.STATE
source_account_key: str = "credits"
recipient_location: StorageLocation | str = StorageLocation.STATE
recipient_account_key: str = "treasury"
amount: float = 1.0
tax_rate: float | None = None
tax_base_key: str | None = None
exemption_amount: float = 0.0
maximum_tax: float | None = None
allow_partial: bool = True
authority_key: str = "authority"
required_authority: float = 0.0
receipt_memory_key: str = "tax_receipts"
history_memory_key: str = "governance_history"
max_history: int = 500
def check_preconditions(self, agent: Agent, world: World) -> bool:
"""Return whether taxes can be collected."""
if not _is_alive(agent):
return False
if not _has_authority(
agent,
authority_key=self.authority_key,
required_authority=self.required_authority,
):
return False
collector = self._collector(agent, world)
if collector is None or not _is_alive(collector):
return False
return any(self._tax_due(target) > 0 for target in self._targets(agent, world))
def execute(self, agent: Agent, world: World) -> dict[str, Any]:
"""Collect taxes from selected targets."""
if not self.check_preconditions(agent, world):
return _failure(self.name, agent, "preconditions_not_met", world=world)
collector = self._collector(agent, world)
if collector is None:
return _failure(self.name, agent, "collector_not_available", world=world)
step = _world_step(world)
receipts: list[dict[str, Any]] = []
for target in self._targets(agent, world):
due = self._tax_due(target)
collected = _transfer_numeric(
target,
collector,
source_account_key=self.source_account_key,
recipient_account_key=self.recipient_account_key,
amount=due,
source_location=self.source_location,
recipient_location=self.recipient_location,
allow_partial=self.allow_partial,
)
if collected <= 0:
continue
receipt = {
"from": _agent_id(target),
"to": _agent_id(collector),
"collected_by": _agent_id(agent),
"due": due,
"collected": collected,
"source_account_key": self.source_account_key,
"recipient_account_key": self.recipient_account_key,
"step": step,
}
receipts.append(receipt)
_append_bounded(
_ensure_list(_agent_memory(target), self.receipt_memory_key),
copy.deepcopy(receipt),
self.max_history,
)
_append_bounded(
_ensure_list(_agent_memory(collector), self.receipt_memory_key),
copy.deepcopy(receipt),
self.max_history,
)
_record_history(
agent,
history_key=self.history_memory_key,
record={"behavior": self.name, **receipt},
max_history=self.max_history,
)
if not receipts:
return _failure(self.name, agent, "nothing_collected", world=world)
total_collected = sum(_as_float(receipt["collected"]) for receipt in receipts)
logger.debug(
"Agent %s collected %.3f total tax from %s target(s)",
_agent_id(agent),
total_collected,
len(receipts),
)
return _success(
self.name,
agent,
target_ids=tuple(receipt["from"] for receipt in receipts),
details={
"collector_id": _agent_id(collector),
"total_collected": total_collected,
"receipt_count": len(receipts),
"receipts": receipts,
},
world=world,
)
def _collector(self, agent: Agent, world: World) -> Agent | None:
"""Return the tax recipient."""
if self.collector_agent_id is None:
return agent
return _find_agent(world, self.collector_agent_id)
def _targets(self, agent: Agent, world: World) -> tuple[Agent, ...]:
"""Return tax targets."""
return _select_targets(
agent,
world,
target_agent_id=self.target_agent_id,
target_types=self.target_types,
max_targets=self.max_targets,
include_self=False,
)
def _tax_due(self, target: Agent) -> float:
"""Compute deterministic tax due for a target."""
if self.tax_rate is not None:
if self.tax_base_key is None:
base = _numeric_balance(
target,
account_key=self.source_account_key,
location=self.source_location,
)
else:
base = _as_float(_read_agent_value(target, self.tax_base_key, 0.0), 0.0)
taxable_base = max(0.0, base - max(0.0, float(self.exemption_amount)))
due = taxable_base * max(0.0, float(self.tax_rate))
else:
due = max(0.0, float(self.amount))
if self.maximum_tax is not None:
due = min(due, max(0.0, float(self.maximum_tax)))
return due
@dataclass
class SubsidizeBehavior(Behavior):
"""Transfer or mint generic numeric support for selected agents.
This behavior can represent subsidies, grants, aid, bailouts, research
funding, healing energy, infrastructure support, compute credits, mana
allocation, or any other governance-driven positive incentive.
"""
name: ClassVar[str] = "subsidize"
target_agent_id: str | None = None
target_types: tuple[str, ...] = ()
max_targets: int = 1000
source_agent_id: str | None = None
require_source_funds: bool = True
source_location: StorageLocation | str = StorageLocation.STATE
source_account_key: str = "treasury"
recipient_location: StorageLocation | str = StorageLocation.STATE
recipient_account_key: str = "credits"
amount: float = 1.0
allow_partial: bool = True
eligibility_constraints: Mapping[str, Any] = field(default_factory=dict)
authority_key: str = "authority"
required_authority: float = 0.0
receipt_memory_key: str = "subsidy_receipts"
history_memory_key: str = "governance_history"
max_history: int = 500
def check_preconditions(self, agent: Agent, world: World) -> bool:
"""Return whether subsidies can be distributed."""
if not _is_alive(agent) or self.amount <= 0:
return False
if not _has_authority(
agent,
authority_key=self.authority_key,
required_authority=self.required_authority,
):
return False
source = self._source(agent, world)
if source is None or not _is_alive(source):
return False
targets = self._eligible_targets(agent, world)
if not targets:
return False
if not self.require_source_funds:
return True
available = _numeric_balance(
source,
account_key=self.source_account_key,
location=self.source_location,
)
if self.allow_partial:
return available > 0
return available >= self.amount
def execute(self, agent: Agent, world: World) -> dict[str, Any]:
"""Distribute subsidies to eligible targets."""
if not self.check_preconditions(agent, world):
return _failure(self.name, agent, "preconditions_not_met", world=world)
source = self._source(agent, world)
if source is None:
return _failure(self.name, agent, "source_not_available", world=world)
step = _world_step(world)
receipts: list[dict[str, Any]] = []
for target in self._eligible_targets(agent, world):
if self.require_source_funds:
granted = _transfer_numeric(
source,
target,
source_account_key=self.source_account_key,
recipient_account_key=self.recipient_account_key,
amount=self.amount,
source_location=self.source_location,
recipient_location=self.recipient_location,
allow_partial=self.allow_partial,
)
else:
granted = _mint_numeric(
target,
account_key=self.recipient_account_key,
location=self.recipient_location,
amount=self.amount,
)
if granted <= 0:
continue
receipt = {
"from": _agent_id(source) if self.require_source_funds else None,
"to": _agent_id(target),
"authorized_by": _agent_id(agent),
"amount": granted,
"source_account_key": self.source_account_key,
"recipient_account_key": self.recipient_account_key,
"minted": not self.require_source_funds,
"step": step,
}
receipts.append(receipt)
_append_bounded(
_ensure_list(_agent_memory(target), self.receipt_memory_key),
copy.deepcopy(receipt),
self.max_history,
)
_record_history(
agent,
history_key=self.history_memory_key,
record={"behavior": self.name, **receipt},
max_history=self.max_history,
)
if not receipts:
return _failure(self.name, agent, "nothing_granted", world=world)
total_granted = sum(_as_float(receipt["amount"]) for receipt in receipts)
logger.debug(
"Agent %s granted %.3f total subsidy to %s target(s)",
_agent_id(agent),
total_granted,
len(receipts),
)
return _success(
self.name,
agent,
target_ids=tuple(receipt["to"] for receipt in receipts),
details={
"source_id": _agent_id(source),
"total_granted": total_granted,
"receipt_count": len(receipts),
"receipts": receipts,
},
world=world,
)
def _source(self, agent: Agent, world: World) -> Agent | None:
"""Return the subsidy source."""
if self.source_agent_id is None:
return agent
return _find_agent(world, self.source_agent_id)
def _eligible_targets(self, agent: Agent, world: World) -> tuple[Agent, ...]:
"""Return subsidy targets that satisfy eligibility constraints."""
targets = _select_targets(
agent,
world,
target_agent_id=self.target_agent_id,
target_types=self.target_types,
max_targets=self.max_targets,
include_self=False,
)
if not self.eligibility_constraints:
return targets
return tuple(
target for target in targets if _matches_constraints(target, self.eligibility_constraints)
)
@dataclass
class LitigateBehavior(Behavior):
"""Create and optionally resolve a generic dispute or legal/business case.
This behavior can represent lawsuits, arbitration, guild disputes, trade
complaints, research misconduct hearings, platform appeals, treaty disputes,
or any other structured conflict resolution process.
"""
name: ClassVar[str] = "litigate"
target_agent_id: str | None = None
arbitrator_agent_id: str | None = None
case_id: str | None = None
topic: str = "generic_dispute"
claim: Mapping[str, Any] = field(default_factory=dict)
requested_remedy: Mapping[str, Any] = field(default_factory=dict)
evidence_score: float = 0.0
defense_score: float = 0.0
resolution_threshold: float = 0.0
auto_resolve: bool = True
enforce_immediately: bool = False
damages_amount: float = 0.0
damages_account_key: str = "credits"
claimant_account_key: str | None = None
account_location: StorageLocation | str = StorageLocation.STATE
allow_partial_remedy: bool = True
cases_location: StorageLocation | str = StorageLocation.MEMORY
cases_key: str = "cases"
history_memory_key: str = "governance_history"
max_history: int = 500
def check_preconditions(self, agent: Agent, world: World) -> bool:
"""Return whether a dispute can be filed."""
if not _is_alive(agent) or not self.topic:
return False
respondent = _find_agent(world, self.target_agent_id)
if respondent is None or not _is_alive(respondent):
return False
if self.arbitrator_agent_id is not None:
arbitrator = _find_agent(world, self.arbitrator_agent_id)
if arbitrator is None or not _is_alive(arbitrator):
return False
return True
def execute(self, agent: Agent, world: World) -> dict[str, Any]:
"""File and optionally resolve a dispute record."""
if not self.check_preconditions(agent, world):
return _failure(self.name, agent, "preconditions_not_met", world=world)
respondent = _find_agent(world, self.target_agent_id)
if respondent is None:
return _failure(self.name, agent, "respondent_not_available", world=world)
arbitrator = _find_agent(world, self.arbitrator_agent_id)
step = _world_step(world)
claimant_store = _record_store(
agent,
location=self.cases_location,
store_key=self.cases_key,
)
case_id = self.case_id or _generated_record_id(
agent,
behavior=self.name,
category=self.topic,
store=claimant_store,
step=step,
suffix=_agent_id(respondent),
)
status = CaseStatus.FILED.value
remedy_collected = 0.0
if self.auto_resolve:
score_delta = float(self.evidence_score) - float(self.defense_score)
if score_delta >= float(self.resolution_threshold):
status = CaseStatus.CLAIMANT_PREVAILS.value
else:
status = CaseStatus.DISMISSED.value
if (
status == CaseStatus.CLAIMANT_PREVAILS.value
and self.enforce_immediately
and self.damages_amount > 0
):
remedy_collected = _transfer_numeric(
respondent,
agent,
source_account_key=self.damages_account_key,
recipient_account_key=self.claimant_account_key or self.damages_account_key,
amount=self.damages_amount,
source_location=self.account_location,
recipient_location=self.account_location,
allow_partial=self.allow_partial_remedy,
)
record = {
"id": case_id,
"topic": self.topic,
"claimant_id": _agent_id(agent),
"respondent_id": _agent_id(respondent),
"arbitrator_id": None if arbitrator is None else _agent_id(arbitrator),
"claim": copy.deepcopy(dict(self.claim)),
"requested_remedy": copy.deepcopy(dict(self.requested_remedy)),
"evidence_score": float(self.evidence_score),
"defense_score": float(self.defense_score),
"resolution_threshold": float(self.resolution_threshold),
"status": status,
"damages_amount": float(self.damages_amount),
"remedy_collected": remedy_collected,
"created_step": step,
"updated_step": step,
}
parties = [agent, respondent]
if arbitrator is not None and _agent_id(arbitrator) not in {_agent_id(agent), _agent_id(respondent)}:
parties.append(arbitrator)
for party in parties:
store = _record_store(
party,
location=self.cases_location,
store_key=self.cases_key,
)
store[case_id] = copy.deepcopy(record)
_record_history(
party,
history_key=self.history_memory_key,
record={"behavior": self.name, "case_id": case_id, "status": status, "step": step},
max_history=self.max_history,
)
logger.debug(
"Agent %s litigated case %s against %s: %s",
_agent_id(agent),
case_id,
_agent_id(respondent),
status,
)
return _success(
self.name,
agent,
target_ids=(_agent_id(respondent),),
record_ids=(case_id,),
details={
"case_id": case_id,
"topic": self.topic,
"status": status,
"arbitrator_id": None if arbitrator is None else _agent_id(arbitrator),
"remedy_collected": remedy_collected,
},
world=world,
)
@dataclass
class ApproveBehavior(Behavior):
"""Create approval, permit, authorization, denial, or revocation records.
This behavior can represent permits, research approvals, market listings,
construction approvals, treaty ratifications, access grants, governance
permissions, platform moderation decisions, or any other authorization.
"""
name: ClassVar[str] = "approve"
target_agent_id: str | None = None
request_id: str | None = None
requested_action: str = "generic_action"
approval_status: ApprovalStatus | str = ApprovalStatus.APPROVED
approval_constraints: Mapping[str, Any] = field(default_factory=dict)
request_metadata: Mapping[str, Any] = field(default_factory=dict)
approvals_location: StorageLocation | str = StorageLocation.MEMORY
approvals_key: str = "approvals"
state_updates_on_approval: Mapping[str, Any] = field(default_factory=dict)
memory_updates_on_approval: Mapping[str, Any] = field(default_factory=dict)
duration_steps: int | None = None
authority_key: str = "authority"
required_authority: float = 0.0
history_memory_key: str = "governance_history"
max_history: int = 500
def check_preconditions(self, agent: Agent, world: World) -> bool:
"""Return whether the actor can issue an approval decision."""
if not _is_alive(agent) or not self.requested_action:
return False
if not _has_authority(
agent,
authority_key=self.authority_key,
required_authority=self.required_authority,
):
return False
target = self._target(agent, world)
return target is not None and _is_alive(target)
def execute(self, agent: Agent, world: World) -> dict[str, Any]:
"""Create an approval decision record for a target."""
if not self.check_preconditions(agent, world):
return _failure(self.name, agent, "preconditions_not_met", world=world)
target = self._target(agent, world)
if target is None:
return _failure(self.name, agent, "target_not_available", world=world)
step = _world_step(world)
store = _record_store(
target,
location=self.approvals_location,
store_key=self.approvals_key,
)
request_id = self.request_id or _generated_record_id(
agent,
behavior=self.name,
category=self.requested_action,
store=store,
step=step,
suffix=_agent_id(target),
)
constraints_met = (
True
if not self.approval_constraints
else _matches_constraints(target, self.approval_constraints)
)
requested_status = (
self.approval_status.value
if isinstance(self.approval_status, ApprovalStatus)
else str(self.approval_status)
)
status = requested_status if constraints_met else ApprovalStatus.DENIED.value
record = {
"id": request_id,
"requested_action": self.requested_action,
"issued_by": _agent_id(agent),
"target_id": _agent_id(target),
"status": status,
"constraints_met": constraints_met,
"constraints": copy.deepcopy(dict(self.approval_constraints)),
"metadata": copy.deepcopy(dict(self.request_metadata)),
"created_step": step,
"updated_step": step,
"expires_step": None
if self.duration_steps is None or step is None
else step + int(self.duration_steps),
}
store[request_id] = record
applied_state_updates: dict[str, Any] = {}
applied_memory_updates: dict[str, Any] = {}
if status == ApprovalStatus.APPROVED.value:
applied_state_updates = _apply_updates(
target,
self.state_updates_on_approval,
default_location=StorageLocation.STATE,
)
applied_memory_updates = _apply_updates(
target,
self.memory_updates_on_approval,
default_location=StorageLocation.MEMORY,
)
history_record = {
"behavior": self.name,
"request_id": request_id,
"requested_action": self.requested_action,
"target_id": _agent_id(target),
"status": status,
"step": step,
}
_record_history(
agent,
history_key=self.history_memory_key,
record=history_record,
max_history=self.max_history,
)
if _agent_id(agent) != _agent_id(target):
_record_history(
target,
history_key=self.history_memory_key,
record=history_record,
max_history=self.max_history,
)
logger.debug(
"Agent %s issued approval decision %s for %s: %s",
_agent_id(agent),
request_id,
_agent_id(target),
status,
)
return _success(
self.name,
agent,
target_ids=(_agent_id(target),),
record_ids=(request_id,),
details={
"request_id": request_id,
"requested_action": self.requested_action,
"status": status,
"constraints_met": constraints_met,
"state_updates": applied_state_updates,
"memory_updates": applied_memory_updates,
},
world=world,
)
def _target(self, agent: Agent, world: World) -> Agent | None:
"""Return the approval target."""
if self.target_agent_id is None:
return agent
return _find_agent(world, self.target_agent_id)
@dataclass
class EnforceBehavior(Behavior):
"""Check compliance and apply generic penalties or updates.
This behavior can represent regulatory enforcement, moderation, inspections,
contract enforcement, court-ordered remedies, treaty enforcement, safety
actions, quota enforcement, or guild discipline.
"""
name: ClassVar[str] = "enforce"
target_agent_id: str | None = None
target_types: tuple[str, ...] = ()
max_targets: int = 1000
regulation_id: str | None = None
regulations_location: StorageLocation | str = StorageLocation.MEMORY
regulations_key: str = "regulations"
compliance_constraints: Mapping[str, Any] = field(default_factory=dict)
require_violation: bool = True
fine_amount: float = 0.0
penalty_account_key: str = "credits"
collector_agent_id: str | None = None
collector_account_key: str = "treasury"
account_location: StorageLocation | str = StorageLocation.STATE
allow_partial_penalty: bool = True
state_updates_on_violation: Mapping[str, Any] = field(default_factory=dict)
memory_updates_on_violation: Mapping[str, Any] = field(default_factory=dict)
authority_key: str = "authority"
required_authority: float = 0.0
violations_memory_key: str = "violations"
history_memory_key: str = "governance_history"
max_history: int = 500
def check_preconditions(self, agent: Agent, world: World) -> bool:
"""Return whether enforcement can be attempted."""
if not _is_alive(agent):
return False
if not _has_authority(
agent,
authority_key=self.authority_key,
required_authority=self.required_authority,
):
return False
collector = self._collector(agent, world)
if collector is None or not _is_alive(collector):
return False
targets = self._targets(agent, world)
if not targets:
return False
if not self.require_violation:
return True
step = _world_step(world)
return any(self._violation_status(agent, target, step)[0] for target in targets)
def execute(self, agent: Agent, world: World) -> dict[str, Any]:
"""Enforce configured constraints or regulation records against targets."""
if not self.check_preconditions(agent, world):
return _failure(self.name, agent, "preconditions_not_met", world=world)
collector = self._collector(agent, world)
if collector is None:
return _failure(self.name, agent, "collector_not_available", world=world)
step = _world_step(world)
enforcement_records: list[dict[str, Any]] = []
for target in self._targets(agent, world):
violation, regulation = self._violation_status(agent, target, step)
if self.require_violation and not violation:
continue
penalties = self._penalties_for(regulation)
collected_penalties: dict[str, float] = {}
for account_key, amount in penalties.items():
collected = _transfer_numeric(
target,
collector,
source_account_key=account_key,
recipient_account_key=self.collector_account_key,
amount=amount,
source_location=self.account_location,
recipient_location=self.account_location,
allow_partial=self.allow_partial_penalty,
)
if collected > 0:
collected_penalties[account_key] = collected
applied_state_updates: dict[str, Any] = {}
applied_memory_updates: dict[str, Any] = {}
if violation:
applied_state_updates = _apply_updates(
target,
self.state_updates_on_violation,
default_location=StorageLocation.STATE,
)
applied_memory_updates = _apply_updates(
target,
self.memory_updates_on_violation,
default_location=StorageLocation.MEMORY,
)
record_id = _generated_record_id(
agent,
behavior=self.name,
category="violation" if violation else "inspection",
store=_record_store(target, location=StorageLocation.MEMORY, store_key=self.violations_memory_key),
step=step,
suffix=_agent_id(target),
)
record = {
"id": record_id,
"target_id": _agent_id(target),
"enforced_by": _agent_id(agent),
"collector_id": _agent_id(collector),
"regulation_id": None if regulation is None else regulation.get("id"),
"violation": violation,
"penalties": penalties,
"collected_penalties": collected_penalties,
"state_updates": applied_state_updates,
"memory_updates": applied_memory_updates,
"step": step,
}
violation_store = _record_store(
target,
location=StorageLocation.MEMORY,
store_key=self.violations_memory_key,
)
violation_store[record_id] = copy.deepcopy(record)
_record_history(
agent,
history_key=self.history_memory_key,
record={"behavior": self.name, **record},
max_history=self.max_history,
)
if _agent_id(agent) != _agent_id(target):
_record_history(
target,
history_key=self.history_memory_key,
record={"behavior": self.name, **record},
max_history=self.max_history,
)
enforcement_records.append(record)
if not enforcement_records:
return _failure(self.name, agent, "nothing_enforced", world=world)
total_collected = sum(
sum(record["collected_penalties"].values()) for record in enforcement_records
)
logger.debug(
"Agent %s completed %s enforcement record(s)",
_agent_id(agent),
len(enforcement_records),
)
return _success(
self.name,
agent,
target_ids=tuple(record["target_id"] for record in enforcement_records),
record_ids=tuple(record["id"] for record in enforcement_records),
details={
"records": enforcement_records,
"total_collected": total_collected,
"collector_id": _agent_id(collector),
},
world=world,
)
def _collector(self, agent: Agent, world: World) -> Agent | None:
"""Return the penalty recipient."""
if self.collector_agent_id is None:
return agent
return _find_agent(world, self.collector_agent_id)
def _targets(self, agent: Agent, world: World) -> tuple[Agent, ...]:
"""Return enforcement targets."""
return _select_targets(
agent,
world,
target_agent_id=self.target_agent_id,
target_types=self.target_types,
max_targets=self.max_targets,
include_self=False,
)
def _violation_status(
self,
agent: Agent,
target: Agent,
step: int | None,
) -> tuple[bool, Mapping[str, Any] | None]:
"""Return whether the target violates the relevant constraints."""
regulation = _find_regulation_record(
agent,
target,
regulation_id=self.regulation_id,
location=self.regulations_location,
regulations_key=self.regulations_key,
)
if regulation is not None and not _regulation_is_active(regulation, step):
return False, regulation
merged_constraints: dict[str, Any] = {}
if regulation is not None:
regulation_constraints = regulation.get("constraints", {})
if isinstance(regulation_constraints, Mapping):
merged_constraints.update(dict(regulation_constraints))
merged_constraints.update(dict(self.compliance_constraints))
if not merged_constraints:
return True, regulation
compliant = _matches_constraints(target, merged_constraints)
return not compliant, regulation
def _penalties_for(self, regulation: Mapping[str, Any] | None) -> dict[str, float]:
"""Return penalties from configured behavior and optional regulation."""
penalties: dict[str, float] = {}
if regulation is not None:
raw_penalties = regulation.get("penalties", {})
if isinstance(raw_penalties, Mapping):
penalties.update(
_normalize_penalties(
raw_penalties,
default_account_key=self.penalty_account_key,
)
)
if self.fine_amount > 0:
penalties[self.penalty_account_key] = (
penalties.get(self.penalty_account_key, 0.0) + float(self.fine_amount)
)
return penalties
Regulate = RegulateBehavior
Tax = TaxBehavior
Subsidize = SubsidizeBehavior
Litigate = LitigateBehavior
Approve = ApproveBehavior
Enforce = EnforceBehavior
BEHAVIOR_REGISTRY: Mapping[str, type[Behavior]] = MappingProxyType(
{
RegulateBehavior.name: RegulateBehavior,
TaxBehavior.name: TaxBehavior,
SubsidizeBehavior.name: SubsidizeBehavior,
LitigateBehavior.name: LitigateBehavior,
ApproveBehavior.name: ApproveBehavior,
EnforceBehavior.name: EnforceBehavior,
}
)
__all__ = [
"ApprovalStatus",
"Approve",
"ApproveBehavior",
"BEHAVIOR_REGISTRY",
"CaseStatus",
"Enforce",
"EnforceBehavior",
"GovernanceOutcome",
"Litigate",
"LitigateBehavior",
"Regulate",
"RegulateBehavior",
"StorageLocation",
"Subsidize",
"SubsidizeBehavior",
"Tax",
"TaxBehavior",
]