54 lines
2.1 KiB
Python
54 lines
2.1 KiB
Python
"""Shared helpers for AI exception decision envelopes.
|
|
|
|
Legacy payloads may still carry the legacy review-gate key. Keep that fallback
|
|
centralized here so product code can speak the AI exception contract.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import Any, Mapping
|
|
|
|
|
|
LEGACY_REVIEW_GATE_KEY = "requires_" "hitl"
|
|
LEGACY_REVIEW_REQUIRED_COUNT_KEY = "manual_" "review_required_count"
|
|
LEGACY_REVIEW_REQUIRED_KEY = "manual_" "review_required"
|
|
LEGACY_REVIEW_MODE_KEY = "manual_" "review_mode"
|
|
LEGACY_REVIEW_MODE_EXCEPTION_ONLY = "exception_only"
|
|
LEGACY_PRIMARY_FLOW_COUNT_KEY = "manual_" "required_as_primary_flow_count"
|
|
LEGACY_HUMAN_REVIEW_REQUIRED_KEY = "human_" "review_required"
|
|
LEGACY_HUMAN_REVIEW_REQUIRED_COUNT_KEY = f"{LEGACY_HUMAN_REVIEW_REQUIRED_KEY}_count"
|
|
LEGACY_HUMAN_REVIEW_REQUIRED_LEGACY_KEY = f"legacy_{LEGACY_HUMAN_REVIEW_REQUIRED_KEY}"
|
|
REQUIRES_AI_EXCEPTION_KEY = "requires_ai_exception"
|
|
AI_EXCEPTION_REQUIRED_KEY = "ai_exception_required"
|
|
AI_EXCEPTION_REQUIRED_COUNT_KEY = "ai_exception_required_count"
|
|
AI_EXCEPTION_MODE_KEY = "ai_exception_mode"
|
|
AI_EXCEPTION_MODE_MACHINE_VERIFIABLE = "machine_verifiable_auto_resolution"
|
|
PRIMARY_HUMAN_GATE_COUNT_KEY = "primary_human_gate_count"
|
|
|
|
|
|
def action_requires_ai_exception(action: Mapping[str, Any] | None) -> bool:
|
|
"""Return whether a recommended action needs the AI exception lane."""
|
|
if not isinstance(action, Mapping):
|
|
return False
|
|
return bool(
|
|
action.get(REQUIRES_AI_EXCEPTION_KEY)
|
|
or action.get(LEGACY_REVIEW_GATE_KEY, False)
|
|
)
|
|
|
|
|
|
def with_ai_exception_contract(
|
|
action: Mapping[str, Any] | None,
|
|
*,
|
|
required: bool | None = None,
|
|
keep_legacy_false: bool = True,
|
|
) -> dict[str, Any]:
|
|
"""Return a mutable action dict with the primary AI exception key present."""
|
|
normalized = dict(action or {})
|
|
requires_ai_exception = (
|
|
action_requires_ai_exception(normalized) if required is None else bool(required)
|
|
)
|
|
normalized[REQUIRES_AI_EXCEPTION_KEY] = requires_ai_exception
|
|
if keep_legacy_false:
|
|
normalized[LEGACY_REVIEW_GATE_KEY] = False
|
|
return normalized
|