evict 10% more than asked, and return JSON that parses
**Eviction headroom.** Every size reaching eviction is an estimate, and one
landing a few hundred MB short does not fail honestly: the load is admitted,
starts allocating, and dies on a tiny buffer. Measured on zeiss across
2026-10-30/31, each on a load eviction had just reported as satisfied:
Tried to allocate 20.00 MiB … 8.69 MiB is free
Tried to allocate 190.00 MiB … 18.69 MiB is free
Tried to allocate 12.00 MiB … 8.69 MiB is free
Eviction now targets `needed_gb * 1.10`. The headroom is what it TARGETS, never
what it reports: the shortfall warning and the "needs more than the whole card"
verdict both still measure the caller's actual request, so freeing enough for
the load but not the whole margin stays silent. A warning on the padded figure
would fire on every successful eviction and bury the one real warning. 10% of
the request costs at most one more idle model, and scales — a flat margin would
be too small for a 30 GB model and absurd for a 0.1 GB one.
**JSON mode returned JSON that would not parse.** 21 script generations ended
`finish_reason=length` after writing 6000 tokens of well-formed-but-unfinished
JSON for a job needing ~800; one ran 8.5 minutes. Nothing was misconfigured:
max_tokens was the caller's own 6000, the prompt 2414 tokens, the model's n_ctx
32000. `json_object` IS honoured, but its grammar constrains syntax only and
never requires the root object to close, so an array of scenes grows until the
budget ends mid-token.
Two changes, neither touching the caller's max_tokens:
* `json_schema` is now accepted, which bounds the SHAPE so the object must
close. llama-cpp-python takes only `type: json_object` and reads a sibling
`schema` key, while OpenAI nests it under `json_schema` — so the shapes are
translated. Forwarding OpenAI's form verbatim would have silently DISABLED
the grammar (`_grammar_for_response_format` returns None for other types),
which is worse than not supporting it at all.
* When the budget is hit anyway, the open structures are closed so the caller
gets valid JSON holding the scenes that did arrive. It drops a half-written
element rather than closing around it, never invents content, parses its own
output before returning it (an unverifiable repair is not applied), leaves
prose and already-valid JSON alone, and does not rewrite `finish_reason` —
which stays `length`, so a caller that checks still learns it was cut short.
Co-Authored-By:
Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014T3rZozi1Ehk96NG1WesgC
Showing
Please
register
or
sign in
to comment