39 lines
1.5 KiB
Python
39 lines
1.5 KiB
Python
from typing import Dict, Any, Tuple
|
|
from .contract import SafetyContract
|
|
|
|
|
|
def evaluate_action(contract: SafetyContract, state: Dict[str, Any], action: Dict[str, Any]) -> Tuple[str, Dict[str, Any]]:
|
|
"""Evaluate a proposed action against a SafetyContract.
|
|
|
|
Returns a tuple (verdict, payload) where verdict is one of:
|
|
- 'accept' (payload is possibly rewritten action)
|
|
- 'veto' (payload contains reason)
|
|
|
|
This minimal engine performs precondition and budget checks and may
|
|
rewrite actions to a safe alternative when possible.
|
|
"""
|
|
ok, reason = contract.check_preconditions(state, action)
|
|
if not ok:
|
|
return "veto", {"reason": reason}
|
|
|
|
ok, reason = contract.check_budgets(state, action)
|
|
if not ok:
|
|
# attempt a simple rewrite: scale down costs/speeds if present
|
|
if "speed" in action:
|
|
safe_action = dict(action)
|
|
safe_action["speed"] = action["speed"] * 0.5
|
|
# Re-check budgets assuming cost scales with speed linearly
|
|
costs = dict(action.get("costs", {}))
|
|
for k in costs:
|
|
costs[k] = costs[k] * 0.5
|
|
safe_action["costs"] = costs
|
|
ok2, reason2 = contract.check_budgets(state, safe_action)
|
|
if ok2:
|
|
contract.charge_budgets(safe_action)
|
|
return "accept", safe_action
|
|
return "veto", {"reason": reason}
|
|
|
|
# Accept and charge budgets
|
|
contract.charge_budgets(action)
|
|
return "accept", action
|