Files

864 lines
36 KiB
Python
Raw Permalink Normal View History

2026-08-24 08:11:59 -07:00
#!/usr/bin/env python3
"""Provider/model catalog loading, overlays, and semantic validation."""
from __future__ import annotations
import math
import re
from collections.abc import Mapping
from pathlib import Path
from typing import Any
from urllib.parse import urlsplit
from mmo_util import (
config_root,
deep_merge,
install_root,
read_toml,
valid_absolute_uri,
valid_http_header_value,
validate_id,
)
from mmo_version import MMO_SCHEMA_VERSION
ALLOWED_DRIVERS = {
"switchyard",
"codex_builtin",
"codex_custom",
"codex_oss",
"catalog_only",
}
ALLOWED_WIRE_PROTOCOLS = {
"openai_chat",
"openai_responses",
"anthropic_messages",
"codex_builtin",
"codex_oss",
"catalog_only",
}
ALLOWED_BILLING_MODES = {"api", "subscription", "chatgpt_subscription", "local", "catalog_only"}
ALLOWED_MODEL_KINDS = {
"chat",
"vision_chat",
"ocr",
"image_generation",
"video_generation",
"audio_transcription",
"agent_service",
}
ALLOWED_MODALITIES = {"text", "image", "audio", "video", "file"}
ALLOWED_REASONING = {"none", "minimal", "low", "medium", "high", "xhigh", "max", "ultra"}
def user_catalog_root() -> Path:
return config_root() / "catalog.d"
ROUTE_FIELDS = {
"driver",
"name",
"api_operator",
"access_product",
"wire_protocol",
"billing_mode",
"base_url",
"provider_id",
"auth",
"auth_link_mode",
"wire_api",
"credential_envs",
"http_headers",
"env_http_headers",
"extra_headers",
"request_max_retries",
"stream_max_retries",
"stream_idle_timeout_ms",
"max_retries",
"transport_modalities",
"transport_output_modalities",
"tool_calling",
"parallel_tool_calls",
"preserves_tool_media",
"tool_result_modalities",
"supports_documents",
"resource_group",
"inventory",
"openrouter_policy",
}
ROUTE_COMMON_FIELDS = {
"driver",
"name",
"api_operator",
"access_product",
"wire_protocol",
"billing_mode",
"transport_modalities",
"transport_output_modalities",
"tool_calling",
"parallel_tool_calls",
"preserves_tool_media",
"tool_result_modalities",
"supports_documents",
"resource_group",
"inventory",
"openrouter_policy",
}
ROUTE_DRIVER_FIELDS = {
"switchyard": {
"base_url",
"credential_envs",
"extra_headers",
"max_retries",
},
"codex_custom": {
"base_url",
"wire_api",
"credential_envs",
"http_headers",
"env_http_headers",
"request_max_retries",
"stream_max_retries",
"stream_idle_timeout_ms",
},
"codex_builtin": {"provider_id", "auth", "auth_link_mode"},
"codex_oss": {"provider_id"},
# Catalog-only providers retain endpoint/auth facts for inventory and
# operator diagnostics, but none of these fields is emitted for execution.
"catalog_only": {
"base_url",
"wire_api",
"credential_envs",
"auth",
},
}
MODEL_FIELDS = {
"maker",
"route",
"upstream_id",
"display_name",
"description",
"kind",
"agent_compatible",
"context_window",
"max_output_tokens",
"reasoning_levels",
"default_reasoning",
"modalities",
"output_modalities",
"supports_tool_images",
"supports_documents",
"tool_calling",
"supports_custom_tools",
"parallel_tool_calls",
"supports_reasoning_summaries",
"structured_output",
"availability",
"capability_confidence",
"source",
"availability_source",
"capability_source",
"pricing_source",
"inventory",
"resource_group",
"input_cost_per_million",
"cached_input_cost_per_million",
"cache_write_input_cost_per_million",
"output_cost_per_million",
"unit_cost_usd",
"extra_body",
"route_policy",
}
OPENROUTER_POLICY_FIELDS = {
"only",
"order",
"allow_fallbacks",
"require_parameters",
"data_collection",
"zdr",
"quantizations",
"sort",
"max_price",
}
RESOURCE_FIELDS = {"description", "lock_key", "max_active"}
def _reject_unknown_fields(value: Mapping[str, Any], allowed: set[str], label: str) -> None:
unknown = sorted(set(value) - allowed)
if unknown:
raise ValueError(f"{label} has unknown fields: {', '.join(unknown)}")
def _schema_version(value: Any, expected: int, label: str) -> int:
if not isinstance(value, int) or isinstance(value, bool) or value != expected:
raise ValueError(f"unsupported {label} schema_version")
return value
def _nonempty_string(value: Any, label: str) -> str:
if not isinstance(value, str) or not value.strip():
raise ValueError(f"{label} must be a non-empty string")
return value
def _optional_nonempty_string(value: Any, label: str) -> str | None:
if value is None:
return None
return _nonempty_string(value, label)
def _enum_string(value: Any, allowed: set[str], label: str) -> str:
if not isinstance(value, str) or value not in allowed:
raise ValueError(f"{label} must be one of {sorted(allowed)}")
return value
def _load_catalog_fragment(path: Path) -> dict[str, Any]:
data = read_toml(path)
_reject_unknown_fields(
data, {"schema_version", "routes", "models", "resources"}, f"catalog {path}"
)
try:
_schema_version(data.get("schema_version"), MMO_SCHEMA_VERSION, "catalog")
except ValueError as exc:
raise ValueError(f"unsupported catalog schema_version in {path}") from exc
result: dict[str, Any] = {}
for section in ("routes", "models", "resources"):
value = data.get(section, {})
if not isinstance(value, Mapping):
raise ValueError(f"catalog {section!r} must be a table in {path}")
if not all(isinstance(item, Mapping) for item in value.values()):
raise ValueError(f"catalog {section!r} entries must be tables in {path}")
result[section] = value
return result
def load_global_catalog() -> dict[str, Any]:
"""Load the bundled catalog plus deterministic user overlays.
User fragments are merged lexicographically so an operator can override or
extend a provider/model without editing installed files. Profile-local
fragments are applied separately by :func:`load_catalog`.
"""
catalog = _load_catalog_fragment(install_root() / "config" / "catalog.toml")
root = user_catalog_root()
if root.is_dir():
for path in sorted(root.glob("*.toml")):
catalog = deep_merge(catalog, _load_catalog_fragment(path))
return catalog
def validate_catalog_data(catalog: Mapping[str, Any], *, label: str = "catalog") -> dict[str, Any]:
"""Validate one fully merged catalog and all cross-section references."""
if not isinstance(catalog, Mapping):
raise ValueError(f"{label} must be a table")
_reject_unknown_fields(catalog, {"schema_version", "routes", "models", "resources"}, label)
if "schema_version" in catalog:
_schema_version(catalog["schema_version"], MMO_SCHEMA_VERSION, label)
sections: dict[str, Mapping[str, Any]] = {}
for section in ("routes", "models", "resources"):
value = catalog.get(section, {})
if not isinstance(value, Mapping):
raise ValueError(f"{label}.{section} must be a table")
if not all(isinstance(item, Mapping) for item in value.values()):
raise ValueError(f"{label}.{section} entries must be tables")
sections[section] = value
routes = {key: _validate_route(key, value) for key, value in sections["routes"].items()}
resources = _validate_resources(sections["resources"])
models = _validate_models(sections["models"], routes)
for key, route in routes.items():
resource = route.get("resource_group")
if resource is not None and resource not in resources:
raise ValueError(f"route {key}: unknown resource group {resource!r}")
for key, model in models.items():
resource = model.get("resource_group")
if resource is not None and resource not in resources:
raise ValueError(f"model {key}: unknown resource group {resource!r}")
return {"routes": routes, "models": models, "resources": resources}
def validated_global_catalog() -> dict[str, Any]:
"""Return the merged global catalog after full semantic validation."""
return validate_catalog_data(load_global_catalog(), label="global catalog")
def load_catalog(profile_dir: Path, profile_data: Mapping[str, Any]) -> dict[str, Any]:
catalog = load_global_catalog()
profile_catalog = profile_data.get("catalog", "catalog.toml")
if not isinstance(profile_catalog, str) or not profile_catalog:
raise ValueError("profile.catalog must be a non-empty relative path string")
if Path(profile_catalog).is_absolute():
raise ValueError("profile.catalog must be a non-empty relative path string")
path = (profile_dir / profile_catalog).resolve()
if profile_dir not in path.parents:
raise ValueError("profile catalog path escapes the profile pack")
if path.is_file():
catalog = deep_merge(catalog, _load_catalog_fragment(path))
elif "catalog" in profile_data:
raise ValueError(f"explicit profile catalog file is missing: {profile_catalog}")
return catalog
def _string_list(value: Any, label: str, *, allow_empty: bool = True) -> list[str]:
if value is None and allow_empty:
return []
if not isinstance(value, list) or not all(isinstance(item, str) for item in value):
raise ValueError(f"{label} must be an array of strings")
if any(not item.strip() for item in value):
raise ValueError(f"{label} cannot contain empty strings")
if not allow_empty and not value:
raise ValueError(f"{label} cannot be empty")
if len(value) != len(set(value)):
raise ValueError(f"{label} cannot contain duplicates")
return list(value)
def _positive_int(value: Any, label: str, minimum: int = 1, maximum: int = 1_000_000) -> int:
if not isinstance(value, int) or isinstance(value, bool) or not minimum <= value <= maximum:
raise ValueError(f"{label} must be an integer between {minimum} and {maximum}")
return value
_HEADER_NAME = re.compile(r"[!#$%&'*+.^_`|~0-9A-Za-z-]+")
_ENVIRONMENT_NAME = re.compile(r"[A-Za-z_][A-Za-z0-9_]*")
def _validate_http_base_url(value: Any, label: str) -> str:
"""Validate an HTTP API root before downstream endpoint concatenation."""
if not isinstance(value, str) or not valid_absolute_uri(value):
raise ValueError(f"{label}: valid HTTP(S) base_url is required")
try:
parsed = urlsplit(value)
# Accessing ``port`` performs the range and syntax checks that
# ``urlsplit`` intentionally defers.
_parsed_port = parsed.port
except ValueError as exc:
raise ValueError(f"{label}: valid HTTP(S) base_url is required") from exc
if (
parsed.scheme.lower() not in {"http", "https"}
or parsed.hostname is None
or parsed.username is not None
or parsed.password is not None
# Codex 0.149 trims slashes before appending the endpoint path, while
# Switchyard 0.2.0 also normalizes known endpoint suffixes. Neither
# treats a query or fragment embedded in the base as a URI join input.
or "?" in value
or "#" in value
):
raise ValueError(f"{label}: valid HTTP(S) base_url is required")
return value
def _header_map(value: Any, label: str, *, environment_values: bool = False) -> dict[str, str]:
if not isinstance(value, Mapping):
raise ValueError(f"{label} must be a string-to-string table")
result: dict[str, str] = {}
seen: set[str] = set()
for raw_name, raw_value in value.items():
if not isinstance(raw_name, str) or not _HEADER_NAME.fullmatch(raw_name):
raise ValueError(f"{label}: invalid HTTP header name {raw_name!r}")
normalized_name = raw_name.lower()
if normalized_name in seen:
raise ValueError(f"{label}: duplicate case-insensitive HTTP header name {raw_name!r}")
seen.add(normalized_name)
if not isinstance(raw_value, str):
raise ValueError(f"{label}.{raw_name} must be a string")
if environment_values:
if not _ENVIRONMENT_NAME.fullmatch(raw_value):
raise ValueError(
f"{label}.{raw_name}: invalid environment variable name {raw_value!r}"
)
elif not valid_http_header_value(raw_value):
raise ValueError(f"{label}.{raw_name} contains a prohibited control character")
result[raw_name] = raw_value
return result
def _json_compatible_value(value: Any, label: str) -> Any:
"""Validate a value destined for Switchyard's serde_json::Value map."""
if isinstance(value, (str, bool)):
return value
if isinstance(value, int) and not isinstance(value, bool):
if -(2**63) <= value <= 2**63 - 1:
return value
raise ValueError(f"{label} integer is outside the TOML/JSON target range")
if isinstance(value, float):
if math.isfinite(value):
return value
raise ValueError(f"{label} must not contain a non-finite number")
if isinstance(value, list):
return [
_json_compatible_value(item, f"{label}[{index}]") for index, item in enumerate(value)
]
if isinstance(value, Mapping):
result: dict[str, Any] = {}
for key, item in value.items():
if not isinstance(key, str):
raise ValueError(f"{label} object keys must be strings")
result[key] = _json_compatible_value(item, f"{label}.{key}")
return result
raise ValueError(f"{label} must contain only JSON-compatible TOML values")
def _credential_envs(route: Mapping[str, Any], label: str) -> list[str]:
"""Validate a route's ordered credential environment names."""
raw = route.get("credential_envs", [])
values = _string_list(raw, f"{label}.credential_envs")
for value in values:
if not re.fullmatch(r"[A-Za-z_][A-Za-z0-9_]*", value):
raise ValueError(f"{label}: invalid credential environment variable {value!r}")
return list(dict.fromkeys(values))
def _validate_openrouter_policy(value: Any, label: str) -> dict[str, Any] | None:
if value is None:
return None
if not isinstance(value, Mapping):
raise ValueError(f"{label} must be a table")
_reject_unknown_fields(value, OPENROUTER_POLICY_FIELDS, label)
result = dict(value)
for field in ("only", "order", "quantizations"):
if field in result:
result[field] = _string_list(result[field], f"{label}.{field}", allow_empty=False)
for field in ("allow_fallbacks", "require_parameters", "zdr"):
if field in result and not isinstance(result[field], bool):
raise ValueError(f"{label}.{field} must be boolean")
if "data_collection" in result:
result["data_collection"] = _enum_string(
result["data_collection"], {"allow", "deny"}, f"{label}.data_collection"
)
if "sort" in result:
result["sort"] = _enum_string(
result["sort"], {"price", "throughput", "latency"}, f"{label}.sort"
)
if "max_price" in result:
price = result["max_price"]
if not isinstance(price, Mapping):
raise ValueError(f"{label}.max_price must be a table")
unknown = sorted(set(price) - {"prompt", "completion", "request", "image"})
if unknown:
raise ValueError(f"{label}.max_price has unknown fields: {', '.join(unknown)}")
normalized: dict[str, float] = {}
for field, raw in price.items():
if not isinstance(raw, (int, float)) or isinstance(raw, bool) or raw < 0:
raise ValueError(f"{label}.max_price.{field} must be non-negative and finite")
try:
numeric = float(raw)
except OverflowError:
raise ValueError(
f"{label}.max_price.{field} must be non-negative and finite"
) from None
if not math.isfinite(numeric):
raise ValueError(f"{label}.max_price.{field} must be non-negative and finite")
normalized[str(field)] = numeric
result["max_price"] = normalized
return result
def _validate_route(key: str, route: Mapping[str, Any]) -> dict[str, Any]:
validate_id(key, "route id")
_reject_unknown_fields(route, ROUTE_FIELDS, f"route {key}")
driver = _enum_string(route.get("driver"), ALLOWED_DRIVERS, f"route {key}.driver")
unsupported = sorted(set(route) - ROUTE_COMMON_FIELDS - ROUTE_DRIVER_FIELDS[driver])
if unsupported:
raise ValueError(f"route {key}: fields unsupported by driver {driver!r}: {unsupported}")
result = dict(route)
result.setdefault("name", key)
result["name"] = _nonempty_string(result["name"], f"route {key}.name")
for field in ("api_operator", "access_product"):
result[field] = _nonempty_string(result.get(field), f"route {key}.{field}")
result["wire_protocol"] = _enum_string(
result.get("wire_protocol"), ALLOWED_WIRE_PROTOCOLS, f"route {key}.wire_protocol"
)
result["billing_mode"] = _enum_string(
result.get("billing_mode"), ALLOWED_BILLING_MODES, f"route {key}.billing_mode"
)
expected_protocols = {
"switchyard": {"openai_chat", "openai_responses", "anthropic_messages"},
"codex_custom": {"openai_responses"},
"codex_builtin": {"codex_builtin"},
"codex_oss": {"codex_oss"},
"catalog_only": {"catalog_only", "openai_chat", "openai_responses", "anthropic_messages"},
}[driver]
if result["wire_protocol"] not in expected_protocols:
raise ValueError(f"route {key}.wire_protocol is incompatible with driver {driver!r}")
result["openrouter_policy"] = _validate_openrouter_policy(
result.get("openrouter_policy"), f"route {key}.openrouter_policy"
)
if result["openrouter_policy"] is not None and result["api_operator"] != "openrouter":
raise ValueError(f"route {key}: openrouter_policy requires api_operator='openrouter'")
result.setdefault("transport_modalities", ["text"])
result["transport_modalities"] = _string_list(
result["transport_modalities"], f"route {key}.transport_modalities", allow_empty=False
)
unknown_modalities = sorted(set(result["transport_modalities"]) - ALLOWED_MODALITIES)
if unknown_modalities:
raise ValueError(f"route {key}: invalid transport modalities {unknown_modalities}")
result.setdefault(
"transport_output_modalities",
["text", "image", "video", "audio", "file"] if driver == "catalog_only" else ["text"],
)
result["transport_output_modalities"] = _string_list(
result["transport_output_modalities"],
f"route {key}.transport_output_modalities",
allow_empty=False,
)
unknown_output_modalities = sorted(
set(result["transport_output_modalities"]) - ALLOWED_MODALITIES
)
if unknown_output_modalities:
raise ValueError(f"route {key}: invalid output modalities {unknown_output_modalities}")
result.setdefault("tool_calling", driver != "catalog_only")
result.setdefault("parallel_tool_calls", driver != "catalog_only")
result.setdefault(
"preserves_tool_media",
driver in {"codex_builtin", "codex_custom"},
)
result.setdefault(
"tool_result_modalities",
list(result["transport_modalities"]) if result["preserves_tool_media"] else ["text"],
)
result["tool_result_modalities"] = _string_list(
result["tool_result_modalities"],
f"route {key}.tool_result_modalities",
allow_empty=False,
)
unknown_tool_modalities = sorted(set(result["tool_result_modalities"]) - ALLOWED_MODALITIES)
if unknown_tool_modalities:
raise ValueError(f"route {key}: invalid tool-result modalities {unknown_tool_modalities}")
result.setdefault("supports_documents", "file" in result["transport_modalities"])
for boolean_field in (
"tool_calling",
"parallel_tool_calls",
"preserves_tool_media",
"supports_documents",
):
if not isinstance(result[boolean_field], bool):
raise ValueError(f"route {key}.{boolean_field} must be boolean")
if result["parallel_tool_calls"] and not result["tool_calling"]:
raise ValueError(f"route {key}: parallel_tool_calls requires tool_calling")
if not result["preserves_tool_media"] and set(result["tool_result_modalities"]) - {"text"}:
raise ValueError(
f"route {key}: non-text tool_result_modalities require preserves_tool_media=true"
)
result.setdefault("resource_group", None)
result.setdefault("inventory", None)
for field in ("resource_group", "inventory"):
result[field] = _optional_nonempty_string(result[field], f"route {key}.{field}")
credentials = _credential_envs(result, f"route {key}")
result["credential_envs"] = credentials
if driver == "switchyard":
if "extra_headers" in result:
result["extra_headers"] = _header_map(
result["extra_headers"], f"route {key}.extra_headers"
)
result["base_url"] = _validate_http_base_url(result.get("base_url"), f"route {key}")
result.setdefault("max_retries", 1)
result["max_retries"] = _positive_int(
result["max_retries"], f"route {key}.max_retries", 0, 10
)
elif driver == "codex_custom":
if "http_headers" in result:
result["http_headers"] = _header_map(
result["http_headers"], f"route {key}.http_headers"
)
if "env_http_headers" in result:
result["env_http_headers"] = _header_map(
result["env_http_headers"],
f"route {key}.env_http_headers",
environment_values=True,
)
static_names = {name.lower() for name in result.get("http_headers", {})}
environment_names = {name.lower() for name in result.get("env_http_headers", {})}
overlap = sorted(static_names & environment_names)
if overlap:
raise ValueError(
f"route {key} defines headers in both http_headers and env_http_headers: "
+ ", ".join(overlap)
)
result["base_url"] = _validate_http_base_url(result.get("base_url"), f"route {key}")
result.setdefault("wire_api", "responses")
if not isinstance(result["wire_api"], str) or result["wire_api"] != "responses":
raise ValueError(f"route {key}: Codex custom routes require wire_api='responses'")
for field, default, minimum, maximum in (
("request_max_retries", 1, 0, 2**63 - 1),
("stream_max_retries", 1, 0, 2**63 - 1),
("stream_idle_timeout_ms", 600_000, 1_000, 2**63 - 1),
):
result.setdefault(field, default)
result[field] = _positive_int(result[field], f"route {key}.{field}", minimum, maximum)
elif driver == "codex_builtin":
provider_id = result.get("provider_id")
provider_id = _nonempty_string(provider_id, f"route {key}.provider_id")
if provider_id not in {"openai", "amazon-bedrock"}:
raise ValueError(
f"route {key}: Codex built-in provider_id must be openai or amazon-bedrock"
)
result["provider_id"] = provider_id
result.setdefault("auth", "chatgpt" if provider_id == "openai" else "builtin")
expected_auth = "chatgpt" if provider_id == "openai" else "builtin"
if result.get("auth") != expected_auth:
raise ValueError(
f"route {key}: auth must be {expected_auth!r} for built-in {provider_id!r}"
)
if result.get("auth_link_mode") is not None and not isinstance(
result.get("auth_link_mode"), str
):
raise ValueError(f"route {key}: invalid auth_link_mode")
if result.get("auth_link_mode") not in {None, "shared", "copy", "none"}:
raise ValueError(f"route {key}: invalid auth_link_mode")
elif driver == "codex_oss":
provider_id = result.get("provider_id")
if not isinstance(provider_id, str) or provider_id not in {"ollama", "lmstudio"}:
raise ValueError(f"route {key}: codex_oss provider_id must be ollama or lmstudio")
elif driver == "catalog_only":
if "base_url" in result:
result["base_url"] = _validate_http_base_url(result["base_url"], f"route {key}")
for field in ("wire_api", "auth"):
if field in result:
result[field] = _nonempty_string(result[field], f"route {key}.{field}")
header_fields = {"http_headers", "env_http_headers", "extra_headers"}
allowed_header_fields = {
"switchyard": {"extra_headers"},
"codex_custom": {"http_headers", "env_http_headers"},
}.get(driver, set())
unsupported_headers = sorted((header_fields & set(result)) - allowed_header_fields)
if unsupported_headers:
detail = f"header fields are unsupported by driver {driver}"
raise ValueError(f"route {key}: {detail}: {unsupported_headers}")
return result
def validate_model_entry(
key: str, model: Mapping[str, Any], routes: Mapping[str, Any]
) -> dict[str, Any]:
validate_id(key, "model id")
_reject_unknown_fields(model, MODEL_FIELDS, f"model {key}")
route_key = model.get("route")
if not isinstance(route_key, str) or route_key not in routes:
raise ValueError(f"model {key}: unknown route {route_key!r}")
if not key.startswith(f"{route_key}__"):
raise ValueError(
f"model {key}: catalog key must start with exact route namespace "
f"{route_key!r} followed by '__'"
)
if not isinstance(model.get("upstream_id"), str) or not model["upstream_id"].strip():
raise ValueError(f"model {key}: upstream_id is required")
if not isinstance(model.get("maker"), str) or not model["maker"].strip():
raise ValueError(f"model {key}: maker is required")
result = dict(model)
result.setdefault("display_name", key)
result.setdefault("description", "")
result.setdefault("kind", "chat")
result["display_name"] = _nonempty_string(result["display_name"], f"model {key}.display_name")
if not isinstance(result["description"], str):
raise ValueError(f"model {key}.description must be a string")
result["kind"] = _enum_string(result["kind"], ALLOWED_MODEL_KINDS, f"model {key}.kind")
result.setdefault(
"agent_compatible",
result["kind"] in {"chat", "vision_chat"} and routes[route_key]["driver"] != "catalog_only",
)
if not isinstance(result["agent_compatible"], bool):
raise ValueError(f"model {key}.agent_compatible must be boolean")
result.setdefault("context_window", 131072 if result["agent_compatible"] else 0)
result["context_window"] = _positive_int(
result["context_window"],
f"model {key}.context_window",
1024 if result["agent_compatible"] else 0,
20_000_000,
)
result.setdefault("reasoning_levels", ["none", "low", "medium", "high"])
result["reasoning_levels"] = _string_list(
result["reasoning_levels"], f"model {key}.reasoning_levels", allow_empty=False
)
unknown_reasoning = sorted(set(result["reasoning_levels"]) - ALLOWED_REASONING)
if unknown_reasoning:
raise ValueError(f"model {key}: invalid reasoning levels {unknown_reasoning}")
result.setdefault("default_reasoning", result["reasoning_levels"][-1])
if (
not isinstance(result["default_reasoning"], str)
or result["default_reasoning"] not in result["reasoning_levels"]
):
raise ValueError(f"model {key}: default_reasoning is not supported")
route = routes[route_key]
result["route_policy"] = _validate_openrouter_policy(
result.get("route_policy"), f"model {key}.route_policy"
)
if result["route_policy"] is not None and route["api_operator"] != "openrouter":
raise ValueError(f"model {key}: route_policy requires an OpenRouter route")
if "extra_body" in result:
if route["driver"] != "switchyard":
raise ValueError(f"model {key}: extra_body is supported only by Switchyard targets")
if not isinstance(result["extra_body"], Mapping):
raise ValueError(f"model {key}.extra_body must be a table")
result["extra_body"] = _json_compatible_value(
result["extra_body"], f"model {key}.extra_body"
)
result.setdefault("modalities", route.get("transport_modalities", ["text"]))
result["modalities"] = _string_list(
result["modalities"], f"model {key}.modalities", allow_empty=False
)
unknown_modalities = sorted(set(result["modalities"]) - ALLOWED_MODALITIES)
if unknown_modalities:
raise ValueError(f"model {key}: invalid modalities {unknown_modalities}")
missing_input_transport = sorted(set(result["modalities"]) - set(route["transport_modalities"]))
if missing_input_transport:
raise ValueError(
f"model {key}: route transport cannot carry input modalities {missing_input_transport}"
)
result.setdefault("output_modalities", ["text"])
result["output_modalities"] = _string_list(
result["output_modalities"], f"model {key}.output_modalities", allow_empty=False
)
unknown_output_modalities = sorted(set(result["output_modalities"]) - ALLOWED_MODALITIES)
if unknown_output_modalities:
raise ValueError(f"model {key}: invalid output modalities {unknown_output_modalities}")
missing_output_transport = sorted(
set(result["output_modalities"]) - set(route["transport_output_modalities"])
)
if missing_output_transport:
raise ValueError(
f"model {key}: route transport cannot carry output modalities "
f"{missing_output_transport}"
)
result.setdefault(
"supports_tool_images",
"image" in result["modalities"]
and route.get("preserves_tool_media", False)
and "image" in route.get("tool_result_modalities", []),
)
result.setdefault(
"supports_documents",
"file" in result["modalities"] and route.get("supports_documents", False),
)
for boolean_field in ("supports_tool_images", "supports_documents"):
if not isinstance(result[boolean_field], bool):
raise ValueError(f"model {key}.{boolean_field} must be boolean")
if result["supports_tool_images"] and "image" not in result["modalities"]:
raise ValueError(f"model {key}: supports_tool_images requires image input")
if result["supports_documents"] and "file" not in result["modalities"]:
raise ValueError(f"model {key}: supports_documents requires file input")
result.setdefault("tool_calling", route.get("tool_calling", True))
# OpenAI Responses distinguishes schema-defined function tools from
# free-form custom tools. Some compatible endpoints implement the former
# but reject the latter. Keep that narrower capability independent so a
# model can still use shell and MCP function tools without receiving
# Codex's free-form apply_patch tool.
result.setdefault("supports_custom_tools", result["tool_calling"])
result.setdefault("parallel_tool_calls", route.get("parallel_tool_calls", True))
result.setdefault("supports_reasoning_summaries", False)
result.setdefault("structured_output", False)
for boolean_field in (
"tool_calling",
"supports_custom_tools",
"parallel_tool_calls",
"supports_reasoning_summaries",
"structured_output",
):
if not isinstance(result[boolean_field], bool):
raise ValueError(f"model {key}.{boolean_field} must be boolean")
if result["tool_calling"] and not route["tool_calling"]:
raise ValueError(f"model {key}: tool_calling exceeds route transport capability")
if result["supports_custom_tools"] and not result["tool_calling"]:
raise ValueError(f"model {key}: supports_custom_tools requires tool_calling")
if result["parallel_tool_calls"] and not result["tool_calling"]:
raise ValueError(f"model {key}: parallel_tool_calls requires tool_calling")
if result["parallel_tool_calls"] and not route["parallel_tool_calls"]:
raise ValueError(f"model {key}: parallel_tool_calls exceeds route transport capability")
result.setdefault("max_output_tokens", None)
if result["max_output_tokens"] is not None:
result["max_output_tokens"] = _positive_int(
result["max_output_tokens"], f"model {key}.max_output_tokens", 1, 20_000_000
)
result.setdefault("availability", "current")
result.setdefault("capability_confidence", "documented")
result.setdefault("source", "bundled-catalog")
for field in ("availability", "capability_confidence", "source"):
result[field] = _nonempty_string(result[field], f"model {key}.{field}")
for field in (
"availability_source",
"capability_source",
"pricing_source",
"inventory",
"resource_group",
):
if field in result:
result[field] = _optional_nonempty_string(result[field], f"model {key}.{field}")
result.setdefault("resource_group", route.get("resource_group"))
for field in (
"input_cost_per_million",
"cached_input_cost_per_million",
"cache_write_input_cost_per_million",
"output_cost_per_million",
"unit_cost_usd",
):
if field not in result:
continue
value = result[field]
if (
not isinstance(value, (int, float))
or isinstance(value, bool)
or (isinstance(value, float) and not math.isfinite(value))
or value < 0
):
raise ValueError(f"model {key}.{field} must be a non-negative finite number")
return result
def _validate_models(
values: Mapping[str, Any], routes: Mapping[str, Any]
) -> dict[str, dict[str, Any]]:
"""Validate model rows and reject duplicate route/upstream identities."""
result: dict[str, dict[str, Any]] = {}
identities: dict[tuple[str, str], str] = {}
for key, value in values.items():
model = validate_model_entry(key, value, routes)
identity = (str(model["route"]), str(model["upstream_id"]))
previous = identities.get(identity)
if previous is not None:
raise ValueError(
f"models {previous!r} and {key!r} duplicate route/upstream binding {identity!r}"
)
identities[identity] = key
result[key] = model
return result
def _validate_resource(key: str, resource: Mapping[str, Any]) -> dict[str, Any]:
validate_id(key, "resource group id")
_reject_unknown_fields(resource, RESOURCE_FIELDS, f"resource {key}")
result = dict(resource)
result.setdefault("description", "")
if not isinstance(result["description"], str):
raise ValueError(f"resource {key}.description must be a string")
result.setdefault("lock_key", key)
if not isinstance(result["lock_key"], str) or not result["lock_key"]:
raise ValueError(f"resource {key}: lock_key is required")
result.setdefault("max_active", 4)
result["max_active"] = _positive_int(
result["max_active"], f"resource {key}.max_active", 1, 1024
)
return result
def _validate_resources(values: Mapping[str, Any]) -> dict[str, dict[str, Any]]:
result = {key: _validate_resource(key, value) for key, value in values.items()}
capacities: dict[str, tuple[str, int]] = {}
for key, resource in result.items():
lock_key = str(resource["lock_key"])
maximum = int(resource["max_active"])
previous = capacities.get(lock_key)
if previous is not None and previous[1] != maximum:
raise ValueError(
f"resources {previous[0]!r} and {key!r} share lock_key {lock_key!r} "
f"with conflicting max_active values {previous[1]} and {maximum}"
)
capacities[lock_key] = (key, maximum)
return result