Skip to content

Tools: Keep string-typed parameters verbatim in qwen3_coder - #513

Merged
turboderp merged 1 commit into
theroyallab:mainfrom
judarange:fix/qwen3-coder-string-params
Nov 3, 2026
Merged

turboderp merged 1 commit into
theroyallab:mainfrom
judarange:fix/qwen3-coder-string-params

Conversation

@judarange

Copy link
Copy Markdown

Problem

coerce_param_value() runs json.loads on every <parameter> value, so a value whose text happens to be valid JSON stops being text. Handing a write tool the contents of a package.json produces an object instead of the string the tool's own schema declares, and the call is rejected:

content: Expected string

Reproduced with Qwen3.8-27B through OpenCode: writing a package.json failed three times in a row, every time the file's first character was {.

Fix

Thread the request's tools through parse_toolcalls() so the qwen3_coder parser can look up each parameter's declared type and skip coercion when the schema says "type": "string".

Deliberately narrow:

  • parameters typed as anything else are still coerced ("limit": {"type": "number"} still yields 100, not "100");
  • parameters absent from the schema are still coerced;
  • callers that pass no tools get exactly the previous behaviour, so nothing outside the chat-completion path changes.

Only qwen3_coder reads the new argument; the other format handlers are untouched.

Tests

tests/test_qwen3_coder_string_params.py, six cases covering both directions — the string-typed value kept verbatim, the other types still coerced, the undeclared parameter still coerced, and the no-tools back-compat path. Run against this branch:

$ python -m unittest tests/test_qwen3_coder_string_params.py
Ran 6 tests in 0.001s
OK

Verified in production on ExLlamaV3 1.6.6 + Qwen3.8-27B EXL3 (tensor parallel, 2 GPUs).

A <parameter> value whose text happens to be valid JSON was always run
through coerce_param_value(), so a `write` tool handed the content of a
package.json received an object instead of the string its own schema
declares, and the call was rejected with "content: Expected string".

Thread the request's tools through parse_toolcalls() so the qwen3_coder
parser can skip coercion for parameters the tool schema types as "string".
Parameters typed otherwise, parameters absent from the schema, and callers
that pass no tools keep the previous behaviour.

Co-Authored-By: Claude Opus 5 <[email protected]>
@turboderp

Copy link
Copy Markdown
Collaborator

Thanks. This is superseded by the streaming tool calls (push in a moment), but merged for attribution.

@turboderp
turboderp merged commit 1abe8db into theroyallab:main Nov 3, 2026
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.

2 participants