Skip to content

fix(tools): recover Qwen calls without losing ordinary text - #2055

Merged
JustVugg merged 1 commit into
JustVugg:devfrom
Altroo:fix/qwen-tool-call-recovery
Oct 16, 2026
Merged

JustVugg merged 1 commit into
JustVugg:devfrom
Altroo:fix/qwen-tool-call-recovery

Conversation

@Altroo

@Altroo Altroo commented Oct 13, 2026

Copy link
Copy Markdown

Summary

Some Qwen replies omit the outer <tool_call> wrapper. Recover the inner function blocks only when they make up the entire reply and refer to declared tools with valid required arguments.

The existing streaming suppressor cannot safely handle that recovery: seeing <function= is not enough to decide whether it is a call or a code example. Buffer ambiguous syntax until parsing finishes, then emit either tool calls or the original text. Apply the same behavior to OpenAI and Anthropic responses.

Also preserve rejected wrapped calls as text, reject duplicate or malformed parameters, and restore nullable/union JSON types without accepting the wrong top-level type. This is not a full JSON Schema validator. Invalid non-string required entries return 400 before generation.

Validation

  • env -u OMP_NUM_THREADS make -C c -j4 check: clean portable CPU build and C tests passed; initial Python suite passed.
  • After the last schema regression was added, env -u OMP_NUM_THREADS make -C c test-python: 2,411 tests ran, 305 skipped, no failures.
  • python3 -m unittest -v tests.test_qwen_tool_validation: all 10 tests passed. Includes real HTTP handlers with deterministic chunked engine output, OpenAI/Anthropic, streaming/non-streaming, valid calls, rejected calls, code examples, and malformed schemas.
  • Qwen template tests with Jinja installed: all 9 passed.
  • Apple Silicon/macOS, upstream dev 88f25a60. No pretrained-model quality, GPU, or performance claim.

Compatibility

  • No new CPU dependencies.
  • No models, binaries, or generated artifacts included.

Related: #1794 introduced Qwen tool support. #1995 addresses a separate falsey top-level tools validation issue; this PR does not replace that change.

@JustVugg
JustVugg merged commit 58c057a into JustVugg:dev Oct 16, 2026
@feranmiomotayo110-oss

Copy link
Copy Markdown

Summary

Some Qwen replies omit the outer <tool_call> wrapper. Recover the inner function blocks only when they make up the entire reply and refer to declared tools with valid required arguments.

The existing streaming suppressor cannot safely handle that recovery: seeing <function= is not enough to decide whether it is a call or a code example. Buffer ambiguous syntax until parsing finishes, then emit either tool calls or the original text. Apply the same behavior to OpenAI and Anthropic responses.

Also preserve rejected wrapped calls as text, reject duplicate or malformed parameters, and restore nullable/union JSON types without accepting the wrong top-level type. This is not a full JSON Schema validator. Invalid non-string required entries return 400 before generation.

Validation

  • env -u OMP_NUM_THREADS make -C c -j4 check: clean portable CPU build and C tests passed; initial Python suite passed.
  • After the last schema regression was added, env -u OMP_NUM_THREADS make -C c test-python: 2,411 tests ran, 305 skipped, no failures.
  • python3 -m unittest -v tests.test_qwen_tool_validation: all 10 tests passed. Includes real HTTP handlers with deterministic chunked engine output, OpenAI/Anthropic, streaming/non-streaming, valid calls, rejected calls, code examples, and malformed schemas.
  • Qwen template tests with Jinja installed: all 9 passed.
  • Apple Silicon/macOS, upstream dev 88f25a60. No pretrained-model quality, GPU, or performance claim.

Compatibility

  • No new CPU dependencies.
  • No models, binaries, or generated artifacts included.

Related: #1794 introduced Qwen tool support. #1995 addresses a separate falsey top-level tools validation issue; this PR does not replace that change.

@feranmiomotayo110-oss

Copy link
Copy Markdown

Summary

Some Qwen replies omit the outer <tool_call> wrapper. Recover the inner function blocks only when they make up the entire reply and refer to declared tools with valid required arguments.

The existing streaming suppressor cannot safely handle that recovery: seeing <function= is not enough to decide whether it is a call or a code example. Buffer ambiguous syntax until parsing finishes, then emit either tool calls or the original text. Apply the same behavior to OpenAI and Anthropic responses.

Also preserve rejected wrapped calls as text, reject duplicate or malformed parameters, and restore nullable/union JSON types without accepting the wrong top-level type. This is not a full JSON Schema validator. Invalid non-string required entries return 400 before generation.

Validation

  • env -u OMP_NUM_THREADS make -C c -j4 check: clean portable CPU build and C tests passed; initial Python suite passed.
  • After the last schema regression was added, env -u OMP_NUM_THREADS make -C c test-python: 2,411 tests ran, 305 skipped, no failures.
  • python3 -m unittest -v tests.test_qwen_tool_validation: all 10 tests passed. Includes real HTTP handlers with deterministic chunked engine output, OpenAI/Anthropic, streaming/non-streaming, valid calls, rejected calls, code examples, and malformed schemas.
  • Qwen template tests with Jinja installed: all 9 passed.
  • Apple Silicon/macOS, upstream dev 88f25a60. No pretrained-model quality, GPU, or performance claim.

Compatibility

  • No new CPU dependencies.
  • No models, binaries, or generated artifacts included.

Related: #1794 introduced Qwen tool support. #1995 addresses a separate falsey top-level tools validation issue; this PR does not replace that Can i cash app you some money

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.

3 participants