tdfs4ds.agent.json_constraints¶
tdfs4ds.agent.json_constraints
¶
Which JSON-constraint syntax does this endpoint actually accept?
There is no single industry parameter for constrained decoding. Every serving stack named the same idea differently, and a gateway accepts only its own:
=========================================== ===============================
response_format={"type":"json_schema"} OpenAI, Azure, Mistral, and any
gateway speaking their API
tools=[...] + tool_choice anything with tool calling
response_format={"type":"json_object"} OpenAI "JSON mode", widely copied
extra_body.guided_json vLLM / SGLang
extra_body.nvext.guided_json NVIDIA NIM
extra_body.grammar HuggingFace TGI
extra_body.format Ollama
=========================================== ===============================
So the accept/reject pattern identifies the engine behind the gateway, which
is the one thing no amount of configuration inspection can tell you. Verified
against api.mistral.ai: json_schema enforced, json_object accepted,
the four vendor extensions all 422.
Two settings in tdfs4ds depend on the answer, and they are different settings for different code paths — this module exists because knowing which one to change requires asking the endpoint:
- :data:
tdfs4ds.STRUCTURED_OUTPUT_METHODdrives the consumer agent and the query optimizer, through langchain'swith_structured_output(see :mod:tdfs4ds.agent.structured_output). - :data:
tdfs4ds.INSTRUCT_MODEL_PROVIDERdrives the documentation generator, throughgenai.documentation._build_provider_llm_caller, which branches on provider to pick the wire parameter above.
Why the raw openai SDK rather than the langchain client: the vendor
extensions travel in extra_body, and the point is to see the endpoint's own
4xx verbatim. A translation layer that normalises or swallows it would defeat
the probe. The HTTP client still comes from
:func:tdfs4ds.agent.embedding._build_http_client, so the proxy and TLS
settings are exactly the ones the real calls use.
Cost: nine chat completions against a real model. That is why
check_configuration() runs this only once a cheaper probe has already
reported trouble, and why it is also exposed on its own::
python -m tdfs4ds.agent.json_constraints
Never prints or returns the API key.
_OPENAI_FAMILY
module-attribute
¶
_OPENAI_FAMILY = ('openai', 'azure', 'azure-openai', 'openai-compatible', 'vllm', 'mistralai', 'ollama', 'litellm')
_SCHEMA
module-attribute
¶
_SCHEMA = {'type': 'object', 'properties': {'intent': {'type': 'string'}, 'confidence': {'type': 'number'}}, 'required': ['intent', 'confidence'], 'additionalProperties': False}
_MESSAGES
module-attribute
¶
_MESSAGES = [{'role': 'user', 'content': "Classify: 'Which features tell me how much a customer spends?'. Answer with intent and confidence."}]
_variants
¶
Return [(key, label, kwargs), ...] — the syntaxes to try, in order.
json_schema is probed twice because strict: true is an OpenAI/Azure
flag that Mistral and most generic gateways reject. Failing only the strict
form is therefore not "no structured output" — it is the difference between
provider openai and provider openai-compatible, which is exactly
what _STRICT_JSON_SCHEMA_PROVIDERS encodes in the documentation path.
_looks_unreachable
¶
True when a failure is about the connection, not about the parameter.
Without this, an endpoint that is simply down reports nine identical "rejected" lines and reads as "this gateway supports no constraint syntax at all" — the opposite of the truth.
_looks_unauthorised
¶
True when the endpoint refused the credential (401/403), not the parameter.
Seen live: an expired LiteLLM key made all nine variants fail with the same 401, and the report then read "tool calling: REJECTED by this endpoint".
_classify
¶
Run one variant and return (verdict, detail). Never raises.
_infer_engine
¶
Name the serving stack behind the gateway, or say it was not identified.
Fail-open by design. A permissive gateway that ignores unknown fields accepts every vendor extension, which makes acceptance prove nothing — that case is reported as such rather than resolved by picking a favourite.
_recommend
¶
Map the pattern onto the two settings that depend on it.
Only a value that differs from the current one is recommended: naming a setting that is already correct reads as an instruction to change it.
probe_json_constraints
¶
Ask the instruct endpoint which JSON-constraint syntaxes it accepts.
Sends nine chat completions (see :func:_variants) and classifies each
as enforced / accepted / rejected / unreachable, then infers
the serving stack from the pattern and names the tdfs4ds setting to change.
Parameters¶
model : str, optional
Overrides tdfs4ds.INSTRUCT_MODEL_MODEL for this probe.
timeout : float, default 30.0
Per-request timeout, in seconds.
display : bool, default True
Print the ASCII report. The return value carries the same information.
Returns¶
dict
{"ok", "status", "endpoint", "model", "variants", "verdicts",
"engine", "recommend", "notes", "detail"}. status is 'ok' /
'failed' / 'skipped'; recommend maps a TDFS4DS_*
variable name (without the prefix) to the value to set, and is empty
when nothing needs changing.
Notes¶
Never raises, and never returns or prints the API key.
format_json_constraints
¶
Render report as plain ASCII.
ASCII because the caller may save it into a support ticket with
open(path, 'w') on an unknown default encoding -- the same rule as
diagnostics._print_report and the Vector Store self-test reproducer.
main
¶
python -m tdfs4ds.agent.json_constraints -- probe and report.
Reads the ordinary tdfs4ds configuration, so a .env in the working
directory is picked up by import tdfs4ds as usual.
Exit code 0 when the sweep ran (or had nothing to probe), 1 when the endpoint could not be reached -- so it is usable as a CI gate.