Repository navigation
server: DSML calls stream from the invoke name, not the first parameter's closer - #2201
Conversation
d19bc8a to
c9e09dc
Compare
|
Superseded — the note below describes the first branch, not this pull request. That branch was a second DSML streamer beside main's; #2191 landed main's own, so the branch was reworked (see the 09:24 comment) into a small change to main's Review status on this head, for whoever reviews it. An independent review (GLM-5.3) ran twice. Round 1 raised six issues, all fixed before the first push here: typed-ness followed the JSON schema instead of the DSML Open, not in this revision: Everything else in the description is measured on this head: the reporter's probe reports 676 argument deltas with the first argument byte at 105 (it reports 1 delta at byte 2249 on main), |
|
Thanks @devopsfortunato for the careful work here, especially pinning the joined pieces against the whole reply at every byte boundary in all three spellings. DSML streaming for #1975 landed on main in the meantime, in #2191, so this branch now adds a second streamer beside the one that's there and no longer applies. The one case main doesn't stream is a call whose first parameter is the long one: main sends that call when the parameter closes, and yours would stream it from the name. If you'd like to keep that, could you rebase it as a small change to main's |
9e10bbc to
47cff9e
Compare
|
Reworked as you asked: the branch is now a small change to main's What it does to the window. Before, the header was withheld until the first parameter closed, so a malformation inside that parameter — a bad Both sides are pinned: four shapes that break before the name still send nothing at any byte (and a later legitimate call still streams), ten that break after it stream the header while Checks on this head: |
aae35a3 to
94f7f0a
Compare
94f7f0a to
a1902b1
Compare
|
CI is green on the final head |
|
Thanks @devopsfortunato. As a small change to main's streamer, with both sides of the window pinned, this is what we hoped for. Please add a line to its CHANGELOG entry saying DSML now streams from the invoke name, unlike GLM and XML, and that a call malformed after its name may stream before the reply keeps it as text. Then it's queued for after the 1.2.3 cut. |
|
Added, as its own
One note on the "unlike GLM and XML" wording, in case you meant something narrower: I read it as the invoke tag being DSML's own, because on main XML already sends its header at This commit touches only |
|
CI note for the record: GitHub created no workflow run for The commit changes one |
|
Thanks @devopsfortunato. The missing run has a simple cause: the branch conflicts with main in |
…er's closer (ashhart#1975) A call whose first parameter is the long one was still silent on a streamed reply: the DSML streamer held a call's header until its first parameter was whole, so a write whose content comes first waited for that content. The header now goes out at the invoke name and the first parameter's key and value stream while they are written; the held-arguments buffer and decide() that deferred them are gone, and cut() no longer needs its header check because a value can only be open after its header is out. The window where the stream has sent a call the whole reply keeps as text now starts at the end of the invoke name instead of at the first parameter's closer: a malformation inside the first parameter leaves a streamed call while the whole reply keeps the block as text. Both sides stay pinned: four block shapes that break before the name send nothing at any byte, ten that break after it stream the header and keep the reply's text, a cut inside the name makes no call while a cut inside the first parameter returns the call it began, and a 2,000-byte first parameter fed three bytes at a time streams its arguments before its closer in all three spellings and joins to the whole reply byte for byte.
21ffabe to
dddf984
Compare
|
Thank you @devopsfortunato. This is merged into main with your commits under your own name, so you're listed as a TensorFold contributor. It ships in the next release, credited to you in the changelog and the release notes. |
What this changes
0311c9280)atc overlap --json: one conflicting file with every overlapping pull request, and it is alwaysCHANGELOG.md's top bullet; no open pull request touchestool_dsml_stream.zigor the test files here (checked withgh pr list --json files). The rebase onto0311c9280resolved the changelog slot and applied the code cleanly.Per your note, this is now a small change to main's
tool_dsml_stream.ziginstead of a second streamer. The invoke's header goes out at its name rather than once its first parameter is whole, so a call whose first parameter is the long one — awrite_filewhose only parameter iscontent— streams while that value is written instead of staying silent until the parameter closes.Dsml.heldanddecide(), which buffered the arguments until the first parameter closed, are deleted;send()writes straight to the deltas;cut()no longer needs its!d.headercheck, because a value can only be open after its header is out. Everything else is main's design: the same spellings, the samerejectedfallback to the buffered containment, the same cut replay and repeated-key behaviour, and the joined arguments still equal the whole reply's byte for byte.The window you asked about. Before, a call's header was withheld until the first parameter closed, so a malformation inside that parameter — a bad
string=flag, junk in its key, a non-JSON typed value, a closer where a parameter belongs — streamed nothing at all. Now the window starts at the end of the invoke name: any such malformation after the name leaves a streamed call while the whole reply keeps the block as text, carrying the arguments written up to the break. A client gains the long first parameter as live output; it loses the guarantee that a call that fails to parse was never announced to it. Both sides are pinned by tests:earlyBreaks— four block shapes that break before the invoke name is whole (an unoffered name, text before the invoke, a name whose quote is not followed by>, a block with no invoke) still send nothing at any byte, and a later legitimate call still streams.lateBreaks— ten shapes that break after the name (bad or missing flags, non-JSON typed values, an unclosed block, a block closer with the invoke open, another spelling's closers, junk between parameters) now stream the header whiletool_parse.parsekeeps the whole block as text; a new test pins that.{"path":"notes).parallel_tool_calls: false) policy still withholds a call whose arguments never closed; the many-call mode shows it.Checks on this head
a1902b1c6python3 tools/zig/lean_check.py, on the base0311c9280and on this head:425and425,0new findings.zig build test-server-cpu --summary all:5/5 steps succeeded; 1057/1058 tests passed (1 skipped), including the new long-first-parameter test, the split break-before/after-name tests, and the renamed cut and single-stream tests whose streamed arguments are now pinned to exact strings rather than substrings.zig build test-golden --summary all:322/335and55/55 equal to server goldens, 0 unexpected differences; no fixture is in the diff.zig fmt --checkon all seven touched files: clean.git diff --check: clean. Files ≤600 lines (largest 349).a1902b1c6—zig16m5s,zig-windows17m31s,zig-macos-dev-tools1m20s,release-paths3m17s,fmt14s and bothbenchmark-clientsjobs pass (No GPU run 42014715450 and Zig format run 42014715362, both conclusion success).zig-macos-dev-tools,zig-windowsandrelease-pathsneed those toolchains; no GPU or checkpoint check applies, since this change reaches no kernel, weight or arithmetic path.Receipt
n/a: the change reaches the wire, not inference. It moves the point at which a call's header delta leaves, not which tokens are produced: no token, logit, kernel, weight or arithmetic path is touched, a reply without a DSML call is byte-identical, and the tests pin that the joined streamed arguments equal the whole reply's.