#4586·baml

0.17.0: `baml.json.json` client option (`request_body`) rejects a map literal — only `baml.json.parse` of a hand-escaped string works

Author: BenSpexCreated Aug 25, 2026Updated Aug 25, 2026

Summary

On 0.17.0, a client option typed baml.json.json | null (e.g. openai.GenericClient.new's request_body) rejects a map literal — the only accepted form we found is baml.json.parse("…") over a hand-escaped JSON string. Escaping JSON inside a BAML string literal is exactly the error-prone step a typed literal should replace.

Reproduce

baml
client Sink = openai.GenericClient.new(
    model = "m",
    base_url = env.VLLM_QWEN_BASE_URL,
    api_key = env.VLLM_API_KEY,
    request_body = { chat_template_kwargs: { enable_thinking: false } },
);
bash
$ BAML_VERSION=0.17.0 baml check --from .
error: mismatched types — expected `baml.json.json`, found `map<string, map<string, bool>>`

Working form:

baml
    request_body = baml.json.parse("{\"chat_template_kwargs\": {\"enable_thinking\": false}}"),

— verified end-to-end against a local HTTP sink: the captured POST /v1/chat/completions body carries "chat_template_kwargs":{"enable_thinking":false} verbatim, merged beside model/temperature/max_tokens. So the feature (arbitrary provider body pass-through) works; only the literal ergonomics are the problem.

Why it matters to a real consumer

zenzy-atlas passes vLLM's chat_template_kwargs {enable_thinking: false} on every call of its Qwen clients (Qwen3.6's chat template defaults thinking ON, which on terse extraction tasks rambles to the token ceiling with empty content — the pass-through is load-bearing, baked into the client registration). On classic 0.15 syntax this was a plain nested map in options. On 0.17 the same intent needs a string-escaped JSON literal in every client that carries it; a typo inside the escaped string (say a missing brace) is only caught at json.parse time rather than by the BAML parser, and the literal is unreadable in review.

Ask

Coerce structurally-JSON-compatible literals (maps/lists/strings/numbers/bools/null) to baml.json.json at the type boundary, or provide a baml.json.of(<literal>) builder — either removes the stringly-typed escape step while keeping the json type distinct.

Environment: Linux x86_64, baml wrapper 0.2.0, toolchain 0.17.0.