feat: capability-based routing (v8)

Policy carries an operator-declared model_capabilities directory
and per-tier requires (tool_calling/reasoning/vision booleans,
min_context_tokens). decide_routing checks the policy tier model
in active mode: capable applies, incapable falls back to a capable
worker default, and if both fail or are unknown it returns
capability_blocked, which the worker turns into a failed task
(v3 tools-gate shape, runner never called). Shadow mode only
annotates the reason, never blocks. Explicit task and worker CLI
models bypass the check by design. Invalid requires drops only
that tier (fail-closed, like invalid tier mode). Dry-run reports
per-tier capability status and blocks on active tiers that fail
or cannot be verified.
This commit is contained in:
host committed 2026-11-04 18:02:20 +00:00
1 parent 362dffba4f
commit cd33a929ca
4 files changed
+616 -11

No files matched your search

+49 -3
View File
@@ -19,7 +19,13 @@ What it reports, per tier (plan / goal / default):
that tier,
* tiers absent from the document (worker default, not routed),
* unknown tier names in the document (ignored by the parser),
* whether any tier would actually activate on next dispatch.
* whether any tier would actually activate on next dispatch,
* capability checks (v8): per tier, whether its model meets
its requires against the policy's model_capabilities
directory -- an active tier that fails or cannot be verified
is a BLOCKER (it would block dispatch at the worker
capability gate); a shadow/off tier with the same problem
is a warning only.
What it does NOT do, honestly:
* It does NOT validate model names against a provider or relay
@@ -56,11 +62,15 @@ import sys
try:
from cloud.models import ROUTING_MODES, ROUTING_TIERS
from cloud.models import parse_routing_policy
from cloud.models import parse_tier_requires
from cloud.models import check_model_capabilities
except ImportError: # run as a script from the repo root
sys.path.insert(0, os.path.join(
os.path.dirname(os.path.abspath(__file__)), ".."))
from cloud.models import ROUTING_MODES, ROUTING_TIERS
from cloud.models import parse_routing_policy
from cloud.models import parse_tier_requires
from cloud.models import check_model_capabilities
def _tier_dropped_reason(raw_entry):
@@ -68,6 +78,9 @@ def _tier_dropped_reason(raw_entry):
if "mode" in raw_entry and \
raw_entry.get("mode") not in ROUTING_MODES:
return "invalid tier mode %r" % (raw_entry.get("mode"),)
if "requires" in raw_entry and \
parse_tier_requires(raw_entry.get("requires")) is None:
return "invalid tier requires %r" % (raw_entry.get("requires"),)
return "no usable model"
if isinstance(raw_entry, str):
return "empty model" if not raw_entry.strip() else "unknown"
@@ -135,6 +148,7 @@ def dry_run_policy_document(data, env_mode_override=None):
# without mutating the parsed policy: a tier with an explicit
# mode keeps it, a tier without one follows the overridden global.
effective_policy_mode = global_mode
cap_blocked = False
for tier in ROUTING_TIERS:
raw_entry = raw_tiers.get(tier) if isinstance(raw_tiers,
dict) else None
@@ -166,11 +180,43 @@ def dry_run_policy_document(data, env_mode_override=None):
mode_source = "global_mode"
status = "active" if mode == "active" else (
"shadow" if mode == "shadow" else "off")
# Capability check (v8): the same check decide_routing
# runs, reported before activation. "not_applicable"
# when the tier carries no requirements; "unknown" when
# requirements exist but the model (or a needed field)
# is absent from the directory.
requires = policy.tier_requirements.get(tier) or {}
if not requires:
cap = {"required": None, "missing": [], "unknown": False,
"status": "not_applicable"}
else:
cap_ok, cap_missing, cap_unknown = check_model_capabilities(
policy.model_capabilities, policy.tiers[tier], requires)
cap = {"required": requires, "missing": cap_missing,
"unknown": cap_unknown,
"status": "ok" if cap_ok else (
"unknown" if cap_unknown else "fail")}
tiers_report[tier] = {
"model": policy.tiers[tier], "mode": mode,
"mode_source": mode_source, "status": status,
"dropped_reason": None,
"dropped_reason": None, "capabilities": cap,
}
if cap["status"] in ("fail", "unknown"):
note = ("tier %r model %r %s capability: %s" % (
tier, policy.tiers[tier],
"cannot verify" if cap["status"] == "unknown"
else "lacks",
", ".join(cap["missing"])))
if status == "active":
# An active tier that fails/unknowns its capability
# check would block dispatch (worker capability
# gate), so it blocks the dry-run too.
cap_blocked = True
warnings.append(note + "; applying this policy "
"would block %r tasks at dispatch" % tier)
else:
warnings.append(note + "; %s mode does not block "
"dispatch" % status)
would_activate = [t for t in ROUTING_TIERS
if tiers_report[t]["status"] == "active"]
would_shadow = [t for t in ROUTING_TIERS
@@ -193,7 +239,7 @@ def dry_run_policy_document(data, env_mode_override=None):
"tasks on next worker dispatch if this policy were "
"applied; this dry-run does not activate anything" %
", ".join(would_activate))
blocked = bool(dropped or unknown)
blocked = bool(dropped or unknown or cap_blocked)
return {
"valid": True, "blocked": blocked,
"version": policy.version, "global_mode": global_mode,