Model & Output Policy
Two agent-level controls that bracket the call: model policy decides what may go upstream, output validation decides whether what came back is usable.Model policy
Four fields on the agent, all optional:Evaluation order
The order matters, because a rewrite changes what the lists see:- No
modelin the body? Ifdefault_modelis set it is written into the body and the request proceeds. If it isn’t, nothing is enforced — the request passes through and the upstream decides (most reject a missing model). model_rewrite— an exact key match on the requested name substitutes the target. The rewritten name is what the lists then match, so you cannot smuggle a denied model in by rewriting to it.model_denylist— a match refuses the request. Denylist beats allowlist; a model on both lists is denied.model_allowlist— when the list is non-empty, a model that matches nothing in it is refused. An empty allowlist means “no allowlist”, not “allow nothing”.
Patterns
Allowlist and denylist entries are globs:* matches any run of characters,
including dashes, anywhere in the name — claude-* matches every Claude model,
*-opus-* matches by family. ? is a literal question mark, not a wildcard.
model_rewrite is not a pattern language: its keys are exact model names.
Patterns are compiled with the platform’s linear-time regex engine, so a pathological
pattern cannot stall a worker.
Both lists fail closed, in opposite directions. A pattern the engine refuses to
compile counts as a match on the denylist (so an unreadable deny rule blocks
rather than silently stopping denying) and as a non-match on the allowlist (so
an unreadable allow rule grants nothing). Either way the request is refused, never
quietly let through. Check your patterns on save rather than discovering this in
production.
Responses
A refused model gets a403 naming the reason and the patterns it could have
matched:
error is model_denylisted or model_not_allowed. allowed is null when the
refusal came from the denylist rather than the allowlist. Every data-plane refusal
uses this { error, error_description } shape — it is not the {data, meta}
envelope the /v1 management API returns, because the data plane speaks your
provider SDK’s protocol, not KnoxCall’s. A rewrite or a default
substitution is silent to the caller — the request succeeds — but is recorded on
the usage row, so the model you are billed for is the model that actually ran.
Day-zero models
Model policy is opt-in. With no allowlist an agent will proxy any model its upstream accepts, which is what makes a new model usable the day it ships — see Providers & day-zero models.Output validation
Set an agent’soutput_schema to a JSON Schema and the gateway validates the
model’s answer against it before the response leaves the building.
What is validated
The gateway extracts the assistant’s text content from the provider response, parses it as JSON and checks it. The supported schema subset is deliberately small —type, required, properties, items, enum — which covers “return
this exact object shape” without a full JSON-Schema engine.
Two cases pass without complaint by design:
- a response with no extractable text content (nothing to validate);
- content that is not JSON, unless the schema’s top-level
typeisobjectorarray— then non-JSON is a violation.
Actions
output_validation_action decides what happens on a violation. Default is warn.
A
warn violation is reported to the caller in a response header only. It does not
write an audit row or a queryable event, so “how often does this agent break its
schema” has no answer on the server side today — read the header in your client if
you need to count them.retry costs a second upstream call, charged like any other. It is worth it for
a flaky structured-output model and not worth it for a model that never gets the
shape right — fix the prompt instead.
A retried response goes through exactly the same downstream stages as a first
response — PII redaction and detokenization, the
canary scan, the cache-store gate — so a retry cannot be a way around a control
that applied to the first answer.