Spaces:
Runtime error
Runtime error
Download behaviors/governance.py from build-small-hackathon/WorldSmithAI: direct link, hf CLI and curl.
- Browser
- Download file 64.2 kB
-
https://huggingface.co/spaces/build-small-hackathon/WorldSmithAI/resolve/4e69866027ef3cd6d5c1d9cb1eeb292bbeb0c9a0/behaviors/governance.py
- Command line
-
hf download hf://spaces/build-small-hackathon/WorldSmithAI@4e69866027ef3cd6d5c1d9cb1eeb292bbeb0c9a0/behaviors/governance.py
-
curl -L -o governance.py https://huggingface.co/spaces/build-small-hackathon/WorldSmithAI/resolve/4e69866027ef3cd6d5c1d9cb1eeb292bbeb0c9a0/behaviors/governance.py
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" | |
| 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() | |
| 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, | |
| ) | |
| 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 | |
| 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) | |
| ) | |
| 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, | |
| ) | |
| 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) | |
| 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", | |
| ] |