Follow-up to #383 (Qwen3-Coder XML tool-argument grammar constraint, merged in #385).
Current behavior (intentional scope-out)
QwenCoderToolArgumentConstraint constrains a <parameter=KEY> value region by type where checkable: bare numbers, enums, booleans, and null are constrained; typed strings / arrays / objects / untyped values are treated as free content (the #378 FreeValue path) — any bytes until </parameter>. So a Coder tool with an array/object parameter has that value's structure unconstrained:
<parameter=tags>
["a", "b", not-valid-json...
</parameter>
The surrounding structure (declared key names, required-once, scalar siblings) is still enforced — only the array/object value contents are free.
Proposed enhancement
Qwen3-Coder renders a non-string argument as JSON inside the parameter tag (e.g. <parameter=tags>\n["a","b"]\n</parameter>). When the schema declares a typed array (with items) or nested object, nest the JSON value sub-machine (already in JsonToolArgumentConstraint's StepArray/StepObject/StepStr/...) inside the Coder value region, terminated by </parameter>, so array element types / nested-object keys are constrained too. Untyped arrays / open objects stay free (current behavior).
Notes
- Niche: most tool params are strings/scalars, which are already handled. File now so the limitation is tracked, not lost.
- The compiled schema (
CompiledNode.Items / CompiledNode.Object) already carries the shape; the Coder constraint currently collapses array/object/Any to FK.Free. The lever is a typed value frame that delegates to the shared JSON value machine with </parameter> as the terminator.
- Must preserve: default-off byte-identical, allocation-free hot path, NativeAOT/InvariantGlobalization.
Follow-up to #383 (Qwen3-Coder XML tool-argument grammar constraint, merged in #385).
Current behavior (intentional scope-out)
QwenCoderToolArgumentConstraintconstrains a<parameter=KEY>value region by type where checkable: bare numbers, enums, booleans, and null are constrained; typed strings / arrays / objects / untyped values are treated as free content (the #378FreeValuepath) — any bytes until</parameter>. So a Coder tool with anarray/objectparameter has that value's structure unconstrained:The surrounding structure (declared key names, required-once, scalar siblings) is still enforced — only the array/object value contents are free.
Proposed enhancement
Qwen3-Coder renders a non-string argument as JSON inside the parameter tag (e.g.
<parameter=tags>\n["a","b"]\n</parameter>). When the schema declares a typedarray(withitems) or nestedobject, nest the JSON value sub-machine (already inJsonToolArgumentConstraint'sStepArray/StepObject/StepStr/...) inside the Coder value region, terminated by</parameter>, so array element types / nested-object keys are constrained too. Untyped arrays / open objects stay free (current behavior).Notes
CompiledNode.Items/CompiledNode.Object) already carries the shape; the Coder constraint currently collapses array/object/Any toFK.Free. The lever is a typed value frame that delegates to the shared JSON value machine with</parameter>as the terminator.