serve stage 2: response_format → per-request grammars → grammar-forced drafts in the multiplexed server (stacked on #148)#192
Conversation
rajpratham1
left a comment
There was a problem hiding this comment.
Thanks for the contribution! This is a substantial feature that adds protocol changes, a JSON Schema → GBNF compiler, grammar handling in the OpenAI server, engine integration, and a large new test suite.
Before this can be approved, I think a few things should be clarified:
-
Backward compatibility
- Please document the protocol change introducing the optional
gbytesfield in theSUBMITheader and confirm compatibility with older clients/servers.
- Please document the protocol change introducing the optional
-
Documentation
- The new
response_formatmodes (json_object,json_schema, andgbnf) should be documented for users, including examples and any limitations.
- The new
-
Testing
- The new tests cover many success cases, but it would be good to add more negative and edge-case tests (very large schemas, malformed GBNF, invalid grammar payloads, nested depth limits, etc.).
-
Performance
- Since grammars are compiled/generated per request, it would be helpful to include some discussion or benchmarks on the overhead for large schemas.
Overall the direction looks promising, but given the size of the change I'd prefer these points to be addressed before approval.
b0b3739 to
f559dbe
Compare
…ed compile overhead Addresses the JustVugg#192 review: server usage documented in docs/grammar-draft.md (incl. back-compat statement for the additive SUBMIT field and the JustVugg#100-class near-tie caveat); gateway pre-checks grammar payloads at 1 MiB (matching the engine's gbytes bound); negative tests for non-dict response_format, empty and oversized grammars, plus an explicit test that malformed GBNF passes the gateway by design (engine fail-soft, draft-source semantics). Measured compile overhead: 7.8 us/request typical schema, 17.9 us at the 32-level nesting cap. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
@rajpratham1 all four points addressed in the two pushes just now (plus a rebase of the whole stack onto current main after the merge wave — and since #176 merged underneath, this branch now sits cleanly on top of it):
🤖 Generated with Claude Code |
|
#111 (GPU resident pipeline) just landed on |
|
Rebased onto current main (e21318e, post-#111/#195/#201/#202) — the stack is now the three stage-2 commits only (the #148 base deduped away after your merge). One conflict resolved in |
5e9e2b8 to
2a2b848
Compare
…ed compile overhead Addresses the JustVugg#192 review: server usage documented in docs/grammar-draft.md (incl. back-compat statement for the additive SUBMIT field and the JustVugg#100-class near-tie caveat); gateway pre-checks grammar payloads at 1 MiB (matching the engine's gbytes bound); negative tests for non-dict response_format, empty and oversized grammars, plus an explicit test that malformed GBNF passes the gateway by design (engine fail-soft, draft-source semantics). Measured compile overhead: 7.8 us/request typical schema, 17.9 us at the 32-level nesting cap. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…avior change) — groundwork for per-request grammars in serve_mux Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…UBMIT -> grammar-forced drafts in the multiplexed server
The OpenAI gateway previously 400'd every response_format; the mux engine path
ran with speculation disabled entirely. Now:
- openai_server.py: response_format {"type":"json_object"} (generic ws-tolerant
JSON grammar), {"type":"json_schema"} (schema forwarded as-is, compiled
engine-side by schema_gbnf.h), and a raw-GBNF {"type":"gbnf"} extension.
Draft-source semantics throughout: a schema the engine cannot compile costs
the speedup, never the request and never the output.
- SUBMIT protocol: optional 7th field gbytes; grammar text appended to the
payload after the prompt. 6-field headers unchanged (back-compatible).
- Engine: per-slot GrDraft (grammar_setup_text/grammar_teardown split out of
the env-driven setup); walkers fed on every emitted token. Grammar-forced
drafting in run_serve_mux for greedy requests: a drafting slot leaves the
shared batch for one forward and runs the proven single-sequence verify path
(kv_bind + step_all) — the same primitives prefill already uses per
submission — then rejoins; rejected drafts' KV entries are overwritten by the
next forward exactly like the existing prefix-truncation path. Sampling
requests never draft (verification under sampling needs rejection resampling;
out of scope).
Tests: 7-field SUBMIT parse cases; response_format->grammar plumbing incl.
fail cases; test doubles updated; generic JSON grammar parse+walk validated
against grammar.h. make test-c green; python suite green except the known
environmental memory_available failure (JustVugg#150 fixes it).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ed compile overhead Addresses the JustVugg#192 review: server usage documented in docs/grammar-draft.md (incl. back-compat statement for the additive SUBMIT field and the JustVugg#100-class near-tie caveat); gateway pre-checks grammar payloads at 1 MiB (matching the engine's gbytes bound); negative tests for non-dict response_format, empty and oversized grammars, plus an explicit test that malformed GBNF passes the gateway by design (engine fail-soft, draft-source semantics). Measured compile overhead: 7.8 us/request typical schema, 17.9 us at the 32-level nesting cap. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2a2b848 to
17c433b
Compare
Completes the seam proposed in #146 and started in #148 (stacked on it — the first two commits are that PR + its ws-tolerance follow-up; review the top two commits here): an OpenAI client sends
response_format, and the batched server turns it into grammar-forced draft speedup, per request, with no GBNF hand-writing anywhere.What lands
openai_server.py):response_format{"type":"json_object"}(ships a generic whitespace-tolerant JSON grammar),{"type":"json_schema"}(schema forwarded verbatim; the engine compiles it viaschema_gbnf.h), plus a raw-GBNF{"type":"gbnf"}extension. Draft-source semantics end to end: an uncompilable schema costs the speedup, never the request, never the output.SUBMITfieldgbytes; grammar text rides the payload after the prompt. 6-field headers unchanged.GrDraft(a mechanical de-globalization commit precedes this), lifecycle owned by slot reuse, walkers fed on every emitted token. Grammar drafting now runs insiderun_serve_muxfor greedy requests: a drafting slot steps out of the shared batch for one forward and uses the proven single-sequence verify path (kv_bind+step_all— the exact primitivesmux_submitalready uses for prefill), then rejoins. No changes tostep_decode_batch. Rejected drafts' KV entries are overwritten by the next forward, same as the existing prefix-truncation path. Sampling requests never draft (rejection-resampling under sampling is out of scope and documented as such).Verified
make test-cgreen (incl. new 7-field parse cases); python suite green except the known environmentalmemory_availablefailure (resource_plan: memory_available() macOS support (fixes 0 on Darwin) #150 fixes it). The generic JSON grammar is parse+walk validated againstgrammar.h(46 rules, recursion, escapes).json_schemarequest →[GRAMMAR] request: 18 rulesarmed and schema-shaped output;json_object→ 46-rule generic grammar armed. The model chose fenced, pretty-printed JSON and the ws-tolerant walker tracked it through the indentation — the SCHEMA=<file.json>: JSON-Schema → GBNF compiler for grammar-forced drafts (follow-up to #70, seam discussed in #146) #148 follow-up doing exactly what it was built for.Honest caveats
GrDraft) — aSTAT-line extension would make the speedup observable per request; happy to add in this PR or a follow-up, your call.🤖 Generated with Claude Code