#!/usr/bin/env python3 """Driver-level validation for operator-defined execution targets.""" from __future__ import annotations VALID_ADAPTERS = frozenset( {"pi", "agy", "opencode", "claude-glm", "claude", "codex"} ) def validate_target_contract(target, path: str, error_type) -> None: if target.adapter not in VALID_ADAPTERS: raise error_type( f"{path}.adapter must be one of {sorted(VALID_ADAPTERS)}; " "a new adapter requires dispatcher driver support" ) local = target.adapter == "pi" expected_class = "local_model" if local else "cloud_model" if target.execution_class != expected_class: raise error_type( f"{path}: {target.adapter} targets must use {expected_class}" ) if target.selfcheck_required != local: raise error_type( f"{path}: selfcheck_required must be {str(local).lower()} " f"for {target.adapter} as the persisted-decision compatibility field" ) if not isinstance(target.selfcheck_full_review, bool): raise error_type(f"{path}: selfcheck.full_review must be a boolean") if not isinstance(target.selfcheck_checklist_review, bool): raise error_type(f"{path}: selfcheck.checklist_review must be a boolean") if target.adapter == "pi": if not target.target.startswith("iop/"): raise error_type(f"{path}: pi target must start with iop/") if target.thinking_level is None: raise error_type(f"{path}: pi target requires thinking_level") if target.reasoning_effort is not None or target.command_model is not None: raise error_type( f"{path}: pi target cannot set reasoning_effort or command_model" ) elif target.thinking_level is not None: raise error_type(f"{path}: thinking_level is only valid for pi") if target.adapter == "agy" and ( target.reasoning_effort is not None or target.command_model is not None ): raise error_type( f"{path}: agy target cannot set reasoning_effort or command_model" ) if target.adapter == "opencode" and ( target.reasoning_effort not in {"medium", "high", "max"} or target.command_model is None ): raise error_type( f"{path}: opencode target requires command_model and " "medium|high|max reasoning_effort" ) if target.adapter == "claude-glm" and ( target.command_model is None or target.reasoning_effort != "xhigh" ): raise error_type( f"{path}: claude-glm target requires command_model and " "xhigh reasoning_effort" ) if target.adapter in {"claude", "codex"} and target.reasoning_effort is None: raise error_type( f"{path}: {target.adapter} target requires reasoning_effort" )