The three per-request prologues (chat_completions, completions,
anthropic_count_tokens) now share one resolver
(mtplx/server/request_policy.py). /v1/completions was a diverged partial
copy; unifying it onto the shared path intentionally changes the following.
Chat and count_tokens are observationally unchanged (see the fidelity notes
at the bottom). The golden matrix
(tests/test_request_observability_golden.py, 13 arms) passes byte-identical
with zero golden-file regeneration — including the plain_completions
arm, because every public-envelope key the shared path emits for completions
is either value-identical to what the generation layer already emitted or
filtered out by PUBLIC_MTPLX_STATS_KEYS.
- Server sampler fallback resolved at the prologue. Server-owned sampler
fields (hints mode, or omitted fields) now resolve to the launch sampler
(
state.args.temperature/top_p/top_k, hard fallbackDEFAULT_TEMPERATURE/DEFAULT_TOP_P/DEFAULT_TOP_K= 0.6/0.95/20 when an arg is unset) before generation, exactly as chat always did, instead of passingNonedown. Why it's correct:_generation_paramsalready applied the samestate.argsdefaults downstream, so the sampled distribution is unchanged whenever the args are set; the request is additionally hardened for the args-unset edge, and the resolved target now reaches_resolve_draft_sampler_for_request(target_temperature=...)— see next bullet. - Draft-sampler resolution sees the true effective target temperature.
Previously a completions request without an explicit temperature handed
target_temperature=Noneto the per-family draft-temperature curve, which then used the launch draft default; now the curve maps the actual effective target (e.g. 0.6), matching chat. On launches without a curve (or with a pinned draft sampler) nothing changes. effective_*sampler telemetry.request_observabilitynow carrieseffective_temperature/effective_top_p/effective_top_k(public values identical to the copies_generation_paramsalready wrote — golden unchanged) pluseffective_presence_penalty/effective_frequency_penalty(internal metrics only; not inPUBLIC_MTPLX_STATS_KEYS).request_presence_penalty/request_frequency_penaltyrecorded when the client sends them (internal metrics; chat parity).client_sampler_fields_ignoredcomputed the chat way. Written only when at least one of the five sampler fields was actually ignored. Previously completions wrote an empty list whenever any non-sampler control (e.g.generation_mode,depth) was ignored.client_control_fields_ignoredis unchanged.- OpenCode sampler/draft override path now runs on completions. It
cannot trigger for a raw-prompt request (it requires a chat transcript with
tools or simple chitchat), so behavior is unchanged today; the two
generation calls now pass
draft_sampler=through (alwaysNoneuntil an override can fire), so the completions and chat lanes are structurally identical. - Client-controls ownership evaluated after prompt encoding (was before).
_client_controls_allowedis a pure function of headers/metadata/env, so this is unobservable; error precedence (empty-prompt 400 → mode 400 → depth 400 → non-finite-sampler 400) is unchanged. - Prompt-scoring lane (
echo+logprobs+max_tokens=0) inherits the richer observability dict (additive sampler telemetry keys). Teacher- forced scoring never samples, so this is telemetry-only; the contract test asserts shape keys, not an exact key set, and still passes.
tests/test_server_openai.py::test_completion_request_controls_are_server_owned_without_overridepinned the old mechanism (temperature/top_p/top_k is Nonereaching generation in hints mode). The invariant it guards — client sampler values must not be applied when the server owns controls — still holds and is now pinned more strongly: the resolved values must equal the server defaults (0.6/0.95/20), never the client's, and the newclient_sampler_fields_ignored+effective_*telemetry is asserted.
- Busy-background 503 order is preserved exactly: the resolver raises
BackgroundBusyBypassat the same pipeline position the inline check occupied (after transcript canonicalization, before thinking/mode/depth resolution), so a busy background request never reaches the later 400-raising steps. - Single-fault requests are byte-identical on chat. The one observable
reordering: mode/depth/non-finite-sampler validation now runs as one unit
ahead of the response_format/strict-tool constraint block and the vision
block. A request with two or more invalid elements straddling that seam
(e.g. invalid
response_formatand out-of-rangedepth) now gets the policy 400 instead of the constraint/vision 400. Status codes are unchanged; only which 400 detail wins on multi-fault requests. - count_tokens keeps its historical shape (deliberately, per the
observational-identity constraint): the REQUESTED toolset is encoded
unfiltered, and no prompt contracts / OpenCode system-prompt replacement
are applied. The resolver's
count_tokensprofile encodes exactly the prompt that endpoint always counted and introduces no new raise paths.