Files
ewoooc/services/ai_exception_contract.py
ogt 71a9ca4f3d
Some checks failed
CD Pipeline / deploy (push) Has been cancelled
Add PChome AI controlled dry-run closeout chain
2026-07-01 13:22:16 +08:00

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