Skip to content

server: restore schema-declared argument types for GLM tool calls#571

Open
solodddd wants to merge 1 commit into
antirez:glm5.2from
solodddd:glm5.2-argtypes
Open

server: restore schema-declared argument types for GLM tool calls#571
solodddd wants to merge 1 commit into
antirez:glm5.2from
solodddd:glm5.2-argtypes

Conversation

@solodddd

Copy link
Copy Markdown

Fixes #569.

Problem

On the glm5.2 branch, the GLM tool-call parser stores every <arg_key>/<arg_value> argument as a JSON string ("max_results":"10", "exclude_domains":"[]"), because GLM's wire format carries no type information — unlike DeepSeek's DSML string="true|false" attribute. Clients that validate tool-call arguments against the tool's JSON schema (Chatwise and anything zod/ajv-based) reject every call with a non-string parameter.

Fix

Schema-aware type restoration, no heuristics:

  • While parsing the request's tool schemas, capture each property's declared "type" alongside the existing property-order bookkeeping (tool_schema_order gains a parallel prop_type array).
  • At client-serialization time, a string argument whose declared type is number/integer/boolean/array/object/null and whose text is exactly one valid JSON value of that kind is emitted raw; everything else (declared strings, undeclared properties, values that don't match their declared type, untyped/union schemas) keeps the current behavior.
  • Applied at all client-facing outputs: chat completions (final + streaming deltas), Responses API items/deltas, and Anthropic tool_use blocks (final + SSE flush). Prompt re-rendering paths are untouched. DeepSeek DSML calls are unaffected (their values are already typed; the coercion only ever unquotes a string whose schema says non-string).

Tests

Added test_openai_tool_args_restore_schema_types covering: number/boolean/array restoration, declared strings staying strings, undeclared properties staying strings, and a value that is not valid JSON of its declared type staying a string.

Per CONTRIBUTING:

  • Machine/backend: Apple M3 Ultra (512 GB), Metal backend, macOS.
  • Model quant: GLM-5.2 routed Q4_K (GLM-5.2-UD-Q4_K_RoutedQ4K.gguf).
  • make — clean build, no new warnings.
  • ./ds4_test — all tracks pass (including --server, which covers the tool-call parsing/serialization touched here).
  • Live verification against a running server, non-streaming and streaming:

Before:

"arguments": "{\"query\":\"...\",\"max_results\":\"10\"}"

After (same request, tool schema declares max_results: number, exclude_domains: array):

"arguments": "{\"query\":\"...\",\"max_results\":10,\"exclude_domains\":[\"example.com\"]}"

No inference backend is touched — the change is confined to request-schema parsing and response serialization — so there is no speed-regression surface.

Developed with the assistance of Claude (Anthropic), reviewed and tested by me.

GLM's tool-call wire format (<arg_key>k</arg_key><arg_value>v</arg_value>)
carries no type information, so the parser stored every argument as a JSON
string ("max_results":"10"), breaking clients that validate tool-call
arguments against the tool schema (zod/ajv etc).

Capture each property's declared "type" while parsing tool schemas, and
restore non-string types at client serialization time: a string value whose
declared type is number/integer/boolean/array/object/null and whose text is
valid JSON of that kind is emitted raw.  Values that don't cleanly match
their declared type, undeclared properties, and untyped schemas keep the
current stringly behavior.  Covers chat completions (final + deltas),
Responses, and Anthropic outputs.

Fixes antirez#569

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant