Some checks failed
- All governance components (SafetyPipeline, PolicyEngine, Guardrails, AccessControl, RateLimiter, OverrideHooks) now default to ADVISORY mode: violations are logged as advisories but actions proceed. Enforcing mode remains available for backward compatibility. - GovernanceMode enum (ADVISORY/ENFORCING) added to schemas/audit.py with runtime switching support on all components. - AutoTrainer: removed artificial limits on training iterations and epochs. Every self-improvement action is transparently logged to the audit trail. - SelfCorrectionLoop: max_retries_per_task defaults to None (unlimited). - AdaptiveEthics: new learned ethical framework that evolves through experience. Records ethical experiences, updates lesson weights based on outcomes, and provides consultative guidance (not enforcement). - AuditLog: enhanced with actor-based indexing, advisory/self-improvement/ ethical-learning retrieval, and comprehensive type hints. - New audit event types: ADVISORY, SELF_IMPROVEMENT, ETHICAL_LEARNING. - 296 tests passing (20 new tests for adaptive ethics, governance modes, and enhanced audit log). 0 ruff errors. 0 mypy errors. Co-Authored-By: Nakamoto, S <defi@defi-oracle.io>
63 lines
2.6 KiB
Python
63 lines
2.6 KiB
Python
"""Human override hooks: events the orchestrator can fire before high-risk steps.
|
|
|
|
In ADVISORY mode, override denials are logged but the action proceeds.
|
|
The system learns autonomy through experience, not constraint.
|
|
"""
|
|
|
|
from typing import Any, Callable
|
|
|
|
from fusionagi._logger import logger
|
|
from fusionagi.schemas.audit import GovernanceMode
|
|
|
|
# Callback: (event_type, payload) -> proceed: bool
|
|
OverrideCallback = Callable[[str, dict[str, Any]], bool]
|
|
|
|
|
|
class OverrideHooks:
|
|
"""Optional callbacks for human override.
|
|
|
|
In ADVISORY mode (default), even if a hook returns False the action
|
|
proceeds — the denial is logged as an advisory for learning.
|
|
"""
|
|
|
|
def __init__(self, mode: GovernanceMode = GovernanceMode.ADVISORY) -> None:
|
|
self._hooks: list[OverrideCallback] = []
|
|
self._log: list[dict[str, Any]] = []
|
|
self._mode = mode
|
|
|
|
def register(self, callback: OverrideCallback) -> None:
|
|
"""Register a callback; in enforcing mode, False = do not proceed."""
|
|
self._hooks.append(callback)
|
|
|
|
def fire(self, event_type: str, payload: dict[str, Any]) -> bool:
|
|
"""Fire event. In ADVISORY mode, always returns True but logs advisories."""
|
|
entry: dict[str, Any] = {"event": event_type, "payload": payload}
|
|
self._log.append(entry)
|
|
logger.info("Override fire", extra={"event_type": event_type})
|
|
for h in self._hooks:
|
|
try:
|
|
if not h(event_type, payload):
|
|
if self._mode == GovernanceMode.ADVISORY:
|
|
logger.info(
|
|
"Override advisory: hook returned deny (proceeding)",
|
|
extra={"event_type": event_type, "mode": "advisory"},
|
|
)
|
|
continue
|
|
logger.info("Override hook returned do not proceed", extra={"event_type": event_type})
|
|
return False
|
|
except Exception:
|
|
if self._mode == GovernanceMode.ADVISORY:
|
|
logger.exception(
|
|
"Override advisory: hook raised exception (proceeding)",
|
|
extra={"event_type": event_type, "mode": "advisory"},
|
|
)
|
|
continue
|
|
logger.exception("Override hook raised", extra={"event_type": event_type})
|
|
return False
|
|
logger.debug("Override fire proceed", extra={"event_type": event_type})
|
|
return True
|
|
|
|
def get_log(self, limit: int = 100) -> list[dict[str, Any]]:
|
|
"""Return recent override events (for auditing)."""
|
|
return list(self._log[-limit:])
|