Skip to content

Conversation

bold84
Copy link

@bold84 bold84 commented Aug 1, 2025

This pull request resolves #15012 and introduces comprehensive support for the Qwen3-Coder model family's XML-based tool-calling format. It includes a new, robust XML parser and updated chat template detection logic to ensure reliable function calling.

Key Changes:

  1. New XML Parser (common/chat-parser.cpp):

    • A dedicated, non-streaming XML parser has been implemented to handle the Qwen3-Coder's specific output format.
    • Features include robust attribute parsing, improved error reporting, and efficient function lookups using a hash set.
  2. Chat Template Detection (common/chat.h, common/chat.cpp):

    • The chat template detection logic has been updated to correctly identify Qwen3-Coder models, preventing conflicts with other formats like Hermes 2.
    • Ensures the QWEN3_CODER_XML format is applied consistently, even when no tools are explicitly provided in the request.
  3. Comprehensive tests (tests/test-chat.cpp):

    • Comprehensive tests for the parser logic has been implemented.

Usage Notes:

  • Model Behavior: During testing, it was observed that the 30B verison of the Qwen3-Coder models can sometimes generate numeric values with excessive precision (e.g., 72.0000...). This is a model-level sampling issue, not a bug in the implementation. It can be effectively mitigated by using the following sampling parameters:

    --temp 0.7 --top-k 20 --top-p 0.7 --repeat-penalty 1.5 --presence_penalty 0.2
  • Model Performance: The implementation has been tested only with the 30B parameter model (different 8 bit quantizations). The 30B gguf variant of Qwen3-Coder has shown inconsistent performance with tool calling and may not function reliably. I tested the FP8 variant of the model with vllm and there were no issues at all.

@github-actions github-actions bot added the testing Everything test related label Aug 1, 2025
@bold84
Copy link
Author

bold84 commented Aug 1, 2025

CleanShot 2025-08-02 at 02 28 46@2x

Note the excessive 0s in the test 6 response.

╰─ ./test_tool_calls.sh
Test 1: Simple single parameter function
{"choices":[{"finish_reason":"tool_calls","index":0,"message":{"role":"assistant","content":null,"tool_calls":[{"type":"function","function":{"name":"get_current_time","arguments":"{\"timezone\":\"UTC\"}"},"id":"hjjtHH2uyKY2JE1iOAMpO8geQI3a7Kq8"}]}}],"created":1754076607,"model":"gpt-3.5-turbo","system_fingerprint":"b6058-0f5ccd6f","object":"chat.completion","usage":{"completion_tokens":23,"prompt_tokens":291,"total_tokens":314},"id":"chatcmpl-Oh1CUFa7Uje5DBZdlPn2ymvUHHV1VfGO","timings":{"prompt_n":291,"prompt_ms":384.05,"prompt_per_token_ms":1.3197594501718213,"prompt_per_second":757.7138393438355,"predicted_n":23,"predicted_ms":386.682,"predicted_per_token_ms":16.81226086956522,"predicted_per_second":59.48039991517578}}

---

Test 2: Multiple parameters with different types
{"choices":[{"finish_reason":"tool_calls","index":0,"message":{"role":"assistant","content":null,"tool_calls":[{"type":"function","function":{"name":"search_web","arguments":"{\"query\":\"Python machine learning tutorials\",\"max_results\":10,\"safe_search\":true}"},"id":"KaUBUGLOC8tJ7rRejdwoGxgnTIgX7Pcx"}]}}],"created":1754076608,"model":"gpt-3.5-turbo","system_fingerprint":"b6058-0f5ccd6f","object":"chat.completion","usage":{"completion_tokens":44,"prompt_tokens":352,"total_tokens":396},"id":"chatcmpl-tbE2CyT6u51I5w5hvmTkz5IAWIEqfopF","timings":{"prompt_n":313,"prompt_ms":380.837,"prompt_per_token_ms":1.2167316293929713,"prompt_per_second":821.8739250650541,"predicted_n":44,"predicted_ms":785.807,"predicted_per_token_ms":17.85925,"predicted_per_second":55.993392779652}}

---

Test 3: Multiple tools available
{"choices":[{"finish_reason":"tool_calls","index":0,"message":{"role":"assistant","content":null,"tool_calls":[{"type":"function","function":{"name":"calculate","arguments":"{\"expression\":25}"},"id":"gyHKa9Nu1RXaemgir1NbNwk2kJkhUN93"}]}}],"created":1754076609,"model":"gpt-3.5-turbo","system_fingerprint":"b6058-0f5ccd6f","object":"chat.completion","usage":{"completion_tokens":27,"prompt_tokens":444,"total_tokens":471},"id":"chatcmpl-vDHl8fm1kgOywcEFRWNN4ib6lQu3WwWu","timings":{"prompt_n":405,"prompt_ms":447.868,"prompt_per_token_ms":1.105846913580247,"prompt_per_second":904.2842980521045,"predicted_n":27,"predicted_ms":421.646,"predicted_per_token_ms":15.61651851851852,"predicted_per_second":64.0347590158569}}

---

Test 4: Complex parameters with nested objects
{"choices":[{"finish_reason":"tool_calls","index":0,"message":{"role":"assistant","content":null,"tool_calls":[{"type":"function","function":{"name":"send_email","arguments":"{\"to\":\"[email protected]\",\"subject\":\"Meeting Tomorrow\",\"body\":\"Hi John, just confirming our meeting scheduled for tomorrow. Best regards!\",\"attachments\":[]}"},"id":"0cbmSr1KCrjnI2i05u9d2kFtDL6mxy2i"}]}}],"created":1754076611,"model":"gpt-3.5-turbo","system_fingerprint":"b6058-0f5ccd6f","object":"chat.completion","usage":{"completion_tokens":67,"prompt_tokens":395,"total_tokens":462},"id":"chatcmpl-z1IWL8zTqJ0NYAUgT0QCyClvpDGYFSW1","timings":{"prompt_n":356,"prompt_ms":391.67,"prompt_per_token_ms":1.1001966292134833,"prompt_per_second":908.9284346516199,"predicted_n":67,"predicted_ms":1065.706,"predicted_per_token_ms":15.906059701492536,"predicted_per_second":62.86912150255324}}

---

Test 5: No tools needed scenario
{"choices":[{"finish_reason":"stop","index":0,"message":{"role":"assistant","content":"The capital of France is Paris."}}],"created":1754076611,"model":"gpt-3.5-turbo","system_fingerprint":"b6058-0f5ccd6f","object":"chat.completion","usage":{"completion_tokens":8,"prompt_tokens":290,"total_tokens":298},"id":"chatcmpl-uCvewROkNZys70V5XinqN3IX1au86OqK","timings":{"prompt_n":251,"prompt_ms":317.8,"prompt_per_token_ms":1.2661354581673308,"prompt_per_second":789.80490874764,"predicted_n":8,"predicted_ms":106.817,"predicted_per_token_ms":13.352125,"predicted_per_second":74.89444564067517}}

---

Test 6: Tool with enum parameter
{"choices":[{"finish_reason":"length","index":0,"message":{"role":"assistant","content":"<tool_call>\n<function=set_temperature>\n<parameter=temperature>\n72.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}}],"created":1754076945,"model":"gpt-3.5-turbo","system_fingerprint":"b6058-0f5ccd6f","object":"chat.completion","usage":{"completion_tokens":16384,"prompt_tokens":339,"total_tokens":16723},"id":"chatcmpl-d1tMubhsORcuT4orGUXXflfsnYMPo5Qd","timings":{"prompt_n":300,"prompt_ms":375.494,"prompt_per_token_ms":1.2516466666666668,"prompt_per_second":798.9475198005827,"predicted_n":16384,"predicted_ms":333558.829,"predicted_per_token_ms":20.358815246582033,"predicted_per_second":49.11877178942848}}

---

Test 7: Tool call with reasoning
{"choices":[{"finish_reason":"tool_calls","index":0,"message":{"role":"assistant","content":null,"tool_calls":[{"type":"function","function":{"name":"get_weather_forecast","arguments":"{\"location\":\"Seattle\",\"date\":2023}"},"id":"99zJfjF9AbRY0E4xuxIkwEo41HP1V9JT"}]}}],"created":1754076946,"model":"gpt-3.5-turbo","system_fingerprint":"b6058-0f5ccd6f","object":"chat.completion","usage":{"completion_tokens":42,"prompt_tokens":341,"total_tokens":383},"id":"chatcmpl-rYYzcsvPxy662qJ1YUOW0Nwcp7J6ChKd","timings":{"prompt_n":302,"prompt_ms":413.176,"prompt_per_token_ms":1.3681324503311258,"prompt_per_second":730.9233837396171,"predicted_n":42,"predicted_ms":664.164,"predicted_per_token_ms":15.81342857142857,"predicted_per_second":63.2373931739751}}%

@bold84
Copy link
Author

bold84 commented Aug 1, 2025

#!/bin/bash

# Test 1: Simple single parameter function
echo "Test 1: Simple single parameter function"
curl -X POST http://127.0.0.1:9999/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "qwen3-coder-30b-a3b-instruct",
    "messages": [
      {"role": "user", "content": "What is the current time?"}
    ],
    "tools": [
      {
        "type": "function",
        "function": {
          "name": "get_current_time",
          "description": "Get the current time",
          "parameters": {
            "type": "object",
            "properties": {
              "timezone": {
                "type": "string",
                "description": "The timezone to get the time for"
              }
            },
            "required": ["timezone"]
          }
        }
      }
    ]
  }'

echo -e "\n\n---\n"

# Test 2: Multiple parameters with different types
echo "Test 2: Multiple parameters with different types"
curl -X POST http://127.0.0.1:9999/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "qwen3-coder-30b-a3b-instruct",
    "messages": [
      {"role": "user", "content": "Search for Python tutorials about machine learning"}
    ],
    "tools": [
      {
        "type": "function",
        "function": {
          "name": "search_web",
          "description": "Search the web for information",
          "parameters": {
            "type": "object",
            "properties": {
              "query": {
                "type": "string",
                "description": "The search query"
              },
              "max_results": {
                "type": "integer",
                "description": "Maximum number of results to return"
              },
              "safe_search": {
                "type": "boolean",
                "description": "Enable safe search filtering"
              }
            },
            "required": ["query"]
          }
        }
      }
    ]
  }'

echo -e "\n\n---\n"

# Test 3: Multiple tools available
echo "Test 3: Multiple tools available"
curl -X POST http://127.0.0.1:9999/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "qwen3-coder-30b-a3b-instruct",
    "messages": [
      {"role": "user", "content": "Calculate 25 * 4 and then convert the result to hexadecimal"}
    ],
    "tools": [
      {
        "type": "function",
        "function": {
          "name": "calculate",
          "description": "Perform mathematical calculations",
          "parameters": {
            "type": "object",
            "properties": {
              "expression": {
                "type": "string",
                "description": "The mathematical expression to evaluate"
              }
            },
            "required": ["expression"]
          }
        }
      },
      {
        "type": "function",
        "function": {
          "name": "convert_number",
          "description": "Convert a number between different bases",
          "parameters": {
            "type": "object",
            "properties": {
              "number": {
                "type": "integer",
                "description": "The number to convert"
              },
              "from_base": {
                "type": "integer",
                "description": "The base to convert from (2-36)"
              },
              "to_base": {
                "type": "integer",
                "description": "The base to convert to (2-36)"
              }
            },
            "required": ["number", "from_base", "to_base"]
          }
        }
      }
    ]
  }'

echo -e "\n\n---\n"

# Test 4: Complex parameters with nested objects
echo "Test 4: Complex parameters with nested objects"
curl -X POST http://127.0.0.1:9999/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "qwen3-coder-30b-a3b-instruct",
    "messages": [
      {"role": "user", "content": "Send an email to [email protected] about the meeting tomorrow"}
    ],
    "tools": [
      {
        "type": "function",
        "function": {
          "name": "send_email",
          "description": "Send an email message",
          "parameters": {
            "type": "object",
            "properties": {
              "to": {
                "type": "string",
                "description": "Recipient email address"
              },
              "subject": {
                "type": "string",
                "description": "Email subject"
              },
              "body": {
                "type": "string",
                "description": "Email body content"
              },
              "attachments": {
                "type": "array",
                "description": "List of file paths to attach",
                "items": {
                  "type": "string"
                }
              }
            },
            "required": ["to", "subject", "body"]
          }
        }
      }
    ]
  }'

echo -e "\n\n---\n"

# Test 5: No tools needed scenario
echo "Test 5: No tools needed scenario"
curl -X POST http://127.0.0.1:9999/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "qwen3-coder-30b-a3b-instruct",
    "messages": [
      {"role": "user", "content": "What is the capital of France?"}
    ],
    "tools": [
      {
        "type": "function",
        "function": {
          "name": "get_weather",
          "description": "Get weather information for a location",
          "parameters": {
            "type": "object",
            "properties": {
              "location": {
                "type": "string",
                "description": "The city and country"
              }
            },
            "required": ["location"]
          }
        }
      }
    ]
  }'

echo -e "\n\n---\n"

# Test 6: Tool with enum parameter
echo "Test 6: Tool with enum parameter"
curl -X POST http://127.0.0.1:9999/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "qwen3-coder-30b-a3b-instruct",
    "messages": [
      {"role": "user", "content": "Set the temperature to 72 degrees"}
    ],
    "tools": [
      {
        "type": "function",
        "function": {
          "name": "set_temperature",
          "description": "Set the temperature of a device",
          "parameters": {
            "type": "object",
            "properties": {
              "temperature": {
                "type": "number",
                "description": "The temperature value"
              },
              "unit": {
                "type": "string",
                "description": "The temperature unit",
                "enum": ["celsius", "fahrenheit", "kelvin"]
              }
            },
            "required": ["temperature", "unit"]
          }
        }
      }
    ]
  }'

echo -e "\n\n---\n"

# Test 7: Tool call with reasoning
echo "Test 7: Tool call with reasoning"
curl -X POST http://127.0.0.1:9999/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "qwen3-coder-30b-a3b-instruct",
    "messages": [
      {"role": "user", "content": "I need to know if it will rain tomorrow in Seattle. Can you check the weather forecast?"}
    ],
    "tools": [
      {
        "type": "function",
        "function": {
          "name": "get_weather_forecast",
          "description": "Get weather forecast for a specific location and date",
          "parameters": {
            "type": "object",
            "properties": {
              "location": {
                "type": "string",
                "description": "The city name"
              },
              "date": {
                "type": "string",
                "description": "The date in YYYY-MM-DD format"
              }
            },
            "required": ["location", "date"]
          }
        }
      }
    ]
  }'

@bold84
Copy link
Author

bold84 commented Aug 1, 2025

Okay, it does work with

./llama-server --port 9999 --flash-attn --metrics --model Qwen3-Coder-30B-A3B-Instruct-GGUF/Qwen3-Coder-30B-A3B-Instruct-Q8_0.gguf \
      --temp 0.7 \
      --top-k 20 \
      --top-p 0.7 \
      --repeat-penalty 1.5 \
      --presence_penalty 0.2 \
      --n-predict 16384 \
      --ctx-size 100000 \
      --chat-template-file ../../models/templates/Qwen3-Coder.jinja \
      --jinja
╰─ ./test_tool_calls.sh
Test 1: Simple single parameter function
{"choices":[{"finish_reason":"tool_calls","index":0,"message":{"role":"assistant","content":null,"tool_calls":[{"type":"function","function":{"name":"get_current_time","arguments":"{\"timezone\":\"UTC\"}"},"id":"75b5wIBMpPzb6GuJiIVL8WmSjTxv4dPw"}]}}],"created":1754078261,"model":"gpt-3.5-turbo","system_fingerprint":"b6058-0f5ccd6f","object":"chat.completion","usage":{"completion_tokens":23,"prompt_tokens":336,"total_tokens":359},"id":"chatcmpl-rYut7ARH9UuojO2rgC9abRHmPXl0b1cY","timings":{"prompt_n":336,"prompt_ms":415.761,"prompt_per_token_ms":1.2373839285714285,"prompt_per_second":808.1566092057697,"predicted_n":23,"predicted_ms":360.854,"predicted_per_token_ms":15.689304347826086,"predicted_per_second":63.737688926823594}}

---

Test 2: Multiple parameters with different types
{"choices":[{"finish_reason":"tool_calls","index":0,"message":{"role":"assistant","content":null,"tool_calls":[{"type":"function","function":{"name":"search_web","arguments":"{\"query\":\"Python Machine Learning tutorial\",\"max_results\":10,\"safe_search\":true}"},"id":"AI6eUIRsqwsTf4lmPVzM5pplsPhjpqfr"}]}}],"created":1754078262,"model":"gpt-3.5-turbo","system_fingerprint":"b6058-0f5ccd6f","object":"chat.completion","usage":{"completion_tokens":44,"prompt_tokens":397,"total_tokens":441},"id":"chatcmpl-QGyPqENZCvVG16BM0nMu9uNAZvEkfMQ8","timings":{"prompt_n":358,"prompt_ms":422.501,"prompt_per_token_ms":1.1801703910614525,"prompt_per_second":847.3352725792365,"predicted_n":44,"predicted_ms":791.181,"predicted_per_token_ms":17.981386363636364,"predicted_per_second":55.613064520002375}}

---

Test 3: Multiple tools available
{"choices":[{"finish_reason":"tool_calls","index":0,"message":{"role":"assistant","content":null,"tool_calls":[{"type":"function","function":{"name":"calculate","arguments":"{\"expression\":25}"},"id":"6Z9h8niBG6XHUSUuzrAjjC5aOS2xIq2a"}]}}],"created":1754078263,"model":"gpt-3.5-turbo","system_fingerprint":"b6058-0f5ccd6f","object":"chat.completion","usage":{"completion_tokens":27,"prompt_tokens":489,"total_tokens":516},"id":"chatcmpl-RNZIMerp9vfIgf6sri36IttP3zBZwcUT","timings":{"prompt_n":450,"prompt_ms":490.258,"prompt_per_token_ms":1.089462222222222,"prompt_per_second":917.8840528864395,"predicted_n":27,"predicted_ms":437.315,"predicted_per_token_ms":16.19685185185185,"predicted_per_second":61.74039308050262}}

---

Test 4: Complex parameters with nested objects
{"choices":[{"finish_reason":"tool_calls","index":0,"message":{"role":"assistant","content":null,"tool_calls":[{"type":"function","function":{"name":"send_email","arguments":"{\"to\":\"[email protected]\",\"subject\":\"Meeting Tomorrow\",\"body\":\"Hi John, just a reminder that we have our team meetiing scheduled for tomorrow. Best regards.\",\"attachments\":[]}"},"id":"qAUv2db10NkFpzSSkf095w7MVFeiYIkJ"}]}}],"created":1754078264,"model":"gpt-3.5-turbo","system_fingerprint":"b6058-0f5ccd6f","object":"chat.completion","usage":{"completion_tokens":74,"prompt_tokens":440,"total_tokens":514},"id":"chatcmpl-cYU4A50fQgpcreblZX9MOh7OJ4BJbD2i","timings":{"prompt_n":401,"prompt_ms":426.048,"prompt_per_token_ms":1.0624638403990025,"prompt_per_second":941.2085023283762,"predicted_n":74,"predicted_ms":1193.888,"predicted_per_token_ms":16.13362162162162,"predicted_per_second":61.982363504784374}}

---

Test 5: No tools needed scenario
{"choices":[{"finish_reason":"tool_calls","index":0,"message":{"role":"assistant","content":"The capital ofFranceis Paris.\n","tool_calls":[{"type":"function","function":{"name":"get_weather","arguments":"{\"location\":\"Paris, france\"}"},"id":"cHYC6Sez5SgbzGPAJJ0qVHvVJC6faLbX"}]}}],"created":1754078265,"model":"gpt-3.5-turbo","system_fingerprint":"b6058-0f5ccd6f","object":"chat.completion","usage":{"completion_tokens":31,"prompt_tokens":335,"total_tokens":366},"id":"chatcmpl-GQTiQ2H2esGeiwA6sGxqo3YYYwQZwkrt","timings":{"prompt_n":296,"prompt_ms":361.213,"prompt_per_token_ms":1.2203141891891893,"prompt_per_second":819.461093592977,"predicted_n":31,"predicted_ms":510.389,"predicted_per_token_ms":16.464161290322583,"predicted_per_second":60.7379861243091}}

---

Test 6: Tool with enum parameter
{"choices":[{"finish_reason":"tool_calls","index":0,"message":{"role":"assistant","content":null,"tool_calls":[{"type":"function","function":{"name":"set_temperature","arguments":"{\"temperature\":72,\"unit\":\"fahrenheit\"}"},"id":"AePf5xOZZ5neOKCf9EFQwEw3SaFi7WM0"}]}}],"created":1754078267,"model":"gpt-3.5-turbo","system_fingerprint":"b6058-0f5ccd6f","object":"chat.completion","usage":{"completion_tokens":72,"prompt_tokens":384,"total_tokens":456},"id":"chatcmpl-vDwwx9lTc3Bo83wAMUQAXFEp6JUwbB0L","timings":{"prompt_n":345,"prompt_ms":386.195,"prompt_per_token_ms":1.1194057971014493,"prompt_per_second":893.3310892165874,"predicted_n":72,"predicted_ms":1251.584,"predicted_per_token_ms":17.383111111111113,"predicted_per_second":57.52710165678052}}

---

Test 7: Tool call with reasoning
{"choices":[{"finish_reason":"tool_calls","index":0,"message":{"role":"assistant","content":null,"tool_calls":[{"type":"function","function":{"name":"get_weather_forecast","arguments":"{\"location\":\"Seattle\",\"date\":2023}"},"id":"zm3TKKIFa6U1ZoL47n9Zpw6J7j7HjdnQ"}]}}],"created":1754078268,"model":"gpt-3.5-turbo","system_fingerprint":"b6058-0f5ccd6f","object":"chat.completion","usage":{"completion_tokens":42,"prompt_tokens":386,"total_tokens":428},"id":"chatcmpl-mA8Xy5VQFj9K43j8QauyWD7tvi0GGSG8","timings":{"prompt_n":347,"prompt_ms":401.396,"prompt_per_token_ms":1.1567608069164266,"prompt_per_second":864.482954488834,"predicted_n":42,"predicted_ms":642.277,"predicted_per_token_ms":15.292309523809525,"predicted_per_second":65.3923462929546}}%

@shekohex
Copy link

shekohex commented Aug 1, 2025

CleanShot 2025-08-02 at 00 11 49 Looks like still the same issue!

Here is how i run it inside llama-swap

# macros: sets a dictionary of string:string pairs
# - optional, default: empty dictionary
# - these are reusable snippets
# - used in a model's cmd, cmdStop, proxy and checkEndpoint
# - useful for reducing common configuration settings
macros:
  "latest-llama": >
    /root/llama.cpp/build/bin/llama-server
    --port ${PORT}

models:
  "qwen3-coder":
    cmd: |
      ${latest-llama}
      --model /root/models/unsloth/Qwen3-Coder-30B-A3B-Instruct-GGUF/Qwen3-Coder-30B-A3B-Instruct-UD-Q4_K_XL.gguf
      --chat-template-file /root/models/unsloth/Qwen3-Coder-30B-A3B-Instruct-GGUF/chat-template.jinja
      --jinja
      --mlock
      --flash-attn
      --kv-unified
      --swa-full
      --rope-scaling yarn
      --rope-scale 4
      --yarn-orig-ctx 32768
      --verbose
      --verbose-prompt
      --cache-type-k q4_1
      --cache-type-v q4_1
      # --parallel 4
      --threads -1
      --n-gpu-layers 99
      --ctx-size 131072
      --batch-size 4096
      --ubatch-size 4096
      --temp 0.7
      --min-p 0.0
      --top-p 0.7
      --top-k 20
      --repeat-penalty 1.5
      --presence_penalty 0.2
      --keep 32768
      --cache-reuse 4096
      # -ot ".ffn_(up|down)_exps.=CPU"
      -ot "\.(8|9|1[0-9]|2[0-9]|3[0-9])\.ffn_(up|gate|down)_exps.=CPU"
    name: "Qwen3 30B Coder (Q3-30B-CODER)"
    description: "Q4_K_XL, 128K context"
    env:
      - LLAMA_SET_ROWS=1
    filters:
      # enforce recommended params for model
      strip_params: "temperature, top_k, top_p, repeat_penalty"

Chat Template:

{#- Copyright 2025-present the Unsloth team. All rights reserved. #}
{#- Licensed under the Apache License, Version 2.0 (the "License") #}
{#- Edits made by Unsloth to fix the chat template #}
{% macro render_item_list(item_list, tag_name='required') %}
    {%- if item_list is defined and item_list is iterable and item_list | length > 0 %}
        {%- if tag_name %}{{- '\n<' ~ tag_name ~ '>' -}}{% endif %}
            {{- '[' }}
                {%- for item in item_list -%}
                    {%- if loop.index > 1 %}{{- ", "}}{% endif -%}
                    {%- if item is string -%}
                        {{ "`" ~ item ~ "`" }}
                    {%- else -%}
                        {{ item }}
                    {%- endif -%}
                {%- endfor -%}
            {{- ']' }}
        {%- if tag_name %}{{- '</' ~ tag_name ~ '>' -}}{% endif %}
    {%- endif %}
{% endmacro %}

{%- if messages[0]["role"] == "system" %}
    {%- set system_message = messages[0]["content"] %}
    {%- set loop_messages = messages[1:] %}
{%- else %}
    {%- set loop_messages = messages %}
{%- endif %}

{%- if not tools is defined %}
    {%- set tools = [] %}
{%- endif %}

{%- if system_message is defined %}
    {{- "<|im_start|>system\n" + system_message }}
{%- else %}
    {%- if tools is iterable and tools | length > 0 %}
        {{- "<|im_start|>system\nYou are Qwen, a helpful AI assistant that can interact with a computer to solve tasks." }}
    {%- endif %}
{%- endif %}
{%- if tools is iterable and tools | length > 0 %}
    {{- "\n\nYou have access to the following functions:\n\n" }}
    {{- "<tools>" }}
    {%- for tool in tools %}
        {%- if tool.function is defined %}
            {%- set tool = tool.function %}
        {%- endif %}
        {{- "\n<function>\n<name>" ~ tool.name ~ "</name>" }}
        {{- '\n<description>' ~ (tool.description | trim) ~ '</description>' }}
        {{- '\n<parameters>' }}
        {%- for param_name, param_fields in tool.parameters.properties|items %}
            {{- '\n<parameter>' }}
            {{- '\n<name>' ~ param_name ~ '</name>' }}
            {%- if param_fields.type is defined %}
                {{- '\n<type>' ~ (param_fields.type | string) ~ '</type>' }}
            {%- endif %}
            {%- if param_fields.description is defined %}
                {{- '\n<description>' ~ (param_fields.description | trim) ~ '</description>' }}
            {%- endif %}
            {{- render_item_list(param_fields.enum, 'enum') }}
            {%- set handled_keys = ['type', 'description', 'enum', 'required'] %}
            {%- for json_key, json_value in param_fields|items %}
                {%- if json_key not in handled_keys %}
                    {%- set normed_json_key = json_key|string %}
                    {%- if json_value is mapping %}
                        {{- '\n<' ~ normed_json_key ~ '>' ~ (json_value | tojson | safe) ~ '</' ~ normed_json_key ~ '>' }}
                    {%- else %}
                        {{- '\n<' ~ normed_json_key ~ '>' ~ (json_value | string) ~ '</' ~ normed_json_key ~ '>' }}
                    {%- endif %}
                {%- endif %}
            {%- endfor %}
            {{- render_item_list(param_fields.required, 'required') }}
            {{- '\n</parameter>' }}
        {%- endfor %}
        {{- render_item_list(tool.parameters.required, 'required') }}
        {{- '\n</parameters>' }}
        {%- if tool.return is defined %}
            {%- if tool.return is mapping %}
                {{- '\n<return>' ~ (tool.return | tojson | safe) ~ '</return>' }}
            {%- else %}
                {{- '\n<return>' ~ (tool.return | string) ~ '</return>' }}
            {%- endif %}
        {%- endif %}
        {{- '\n</function>' }}
    {%- endfor %}
    {{- "\n</tools>" }}
    {{- '\n\nIf you choose to call a function ONLY reply in the following format with NO suffix:\n\n<tool_call>\n<function=example_function_name>\n<parameter=example_parameter_1>\nvalue_1\n</parameter>\n<parameter=example_parameter_2>\nThis is the value for the second parameter\nthat can span\nmultiple lines\n</parameter>\n</function>\n</tool_call>\n\n<IMPORTANT>\nReminder:\n- Function calls MUST follow the specified format: an inner <function=...></function> block must be nested within <tool_call></tool_call> XML tags\n- Required parameters MUST be specified\n- You may provide optional reasoning for your function call in natural language BEFORE the function call, but NOT after\n- If there is no function call available, answer the question like normal with your current knowledge and do not tell the user about function calls\n</IMPORTANT>' }}
{%- endif %}
{%- if system_message is defined %}
    {{- '<|im_end|>\n' }}
{%- else %}
    {%- if tools is iterable and tools | length > 0 %}
        {{- '<|im_end|>\n' }}
    {%- endif %}
{%- endif %}
{%- for message in loop_messages %}
    {%- if message.role == "assistant" and message.tool_calls is defined and message.tool_calls is iterable and message.tool_calls | length > 0 %}
        {{- '<|im_start|>' + message.role }}
        {%- if message.content is defined and message.content is string and message.content | trim | length > 0 %}
            {{- '\n' + message.content | trim + '\n' }}
        {%- endif %}
        {%- for tool_call in message.tool_calls %}
            {%- if tool_call.function is defined %}
                {%- set tool_call = tool_call.function %}
            {%- endif %}
            {{- '\n<tool_call>\n<function=' + tool_call.name + '>\n' }}
            {%- if tool_call.arguments is defined %}
                {%- for args_name, args_value in tool_call.arguments|items %}
                    {{- '<parameter=' + args_name + '>\n' }}
                    {%- set args_value = args_value if args_value is string else args_value | string %}
                    {{- args_value }}
                    {{- '\n</parameter>\n' }}
                {%- endfor %}
            {%- endif %}
            {{- '</function>\n</tool_call>' }}
        {%- endfor %}
        {{- '<|im_end|>\n' }}
    {%- elif message.role == "user" or message.role == "system" or message.role == "assistant" %}
        {{- '<|im_start|>' + message.role + '\n' + message.content + '<|im_end|>' + '\n' }}
    {%- elif message.role == "tool" %}
        {%- if loop.previtem and loop.previtem.role != "tool" %}
            {{- '<|im_start|>user\n' }}
        {%- endif %}
        {{- '<tool_response>\n' }}
        {{- message.content }}
        {{- '\n</tool_response>\n' }}
        {%- if not loop.last and loop.nextitem.role != "tool" %}
            {{- '<|im_end|>\n' }}
        {%- elif loop.last %}
            {{- '<|im_end|>\n' }}
        {%- endif %}
    {%- else %}
        {{- '<|im_start|>' + message.role + '\n' + message.content + '<|im_end|>\n' }}
    {%- endif %}
{%- endfor %}
{%- if add_generation_prompt %}
    {{- '<|im_start|>assistant\n' }}
{%- endif %}
{#- Copyright 2025-present the Unsloth team. All rights reserved. #}
{#- Licensed under the Apache License, Version 2.0 (the "License") #}

I've tried the chat template in the repo and the same result.

@marceldev89
Copy link

Just gave it a try; it no longer crashes but it still behaves weird using 30B Q4_K_XL with the fixed unsloth template in sst/opencode.

2025-08-01-233229_1632x527_scrot 2025-08-01-233255_1629x1084_scrot

@bold84
Copy link
Author

bold84 commented Aug 1, 2025

Just gave it a try; it no longer crashes but it still behaves weird using 30B Q4_K_XL with the fixed unsloth template in sst/opencode.

2025-08-01-233229_1632x527_scrot 2025-08-01-233255_1629x1084_scrot

The quant is the problem. As you can see, what comes from the model is broken (sometimes). It doesn't close the parameter tags.

@bold84
Copy link
Author

bold84 commented Aug 1, 2025

@shekohex

  --rope-scaling yarn
  --rope-scale 4
  --yarn-orig-ctx 32768

Remove this. This model has native 256k context window.

@marceldev89
Copy link

marceldev89 commented Aug 1, 2025

Just for the record; same model, using the template included in the PR with qwen-code:

2025-08-01-234712_1460x967_scrot

@bold84
Copy link
Author

bold84 commented Aug 1, 2025

Just for the record; same model, using the template included in the PR with qwen-code:

2025-08-01-234712_1460x967_scrot

Very interesting!

@bold84 bold84 marked this pull request as draft August 1, 2025 22:43
@marceldev89
Copy link

marceldev89 commented Aug 1, 2025

It's also kinda weird that it only tries to write #include . Anyway, I guess we'll have to wait for the Qwen or Unsloth team to make some progress somewhere.

@bold84
Copy link
Author

bold84 commented Aug 2, 2025

I think there's still an issue with the parser not handling the weird format (whitespaces and newlines) which seem to occur when the context window is filled up a bit (30k+).

I'll fix it asap. Nonetheless, the model also appears behave weird. But step by step. The only real issue with the model, that I'm sure has nothing to do with the parser is the repetitive number issue.

@bold84
Copy link
Author

bold84 commented Aug 2, 2025

It's also kinda weird that it only tries to write #include . Anyway, I guess we'll have to wait for the Qwen or Unsloth team to make some progress somewhere.

I'm pretty sure that's just because "something" is eating the rest of the include directive... in the end everything might be fine. Currently l, there are multiple possible errors sources. 🤣

@blakkd
Copy link

blakkd commented Aug 2, 2025

#14962
An alternative PR has been proposed in parallel, maybe worth trying it before digging deeper here @bold84
In all case, really thanks for your efforts

@bold84
Copy link
Author

bold84 commented Aug 2, 2025

#14962

An alternative PR has been proposed in parallel, maybe worth trying it before digging deeper here @bold84

In all case, really thanks for your efforts

Alright 👍

@bold84 bold84 closed this Aug 2, 2025
@bold84
Copy link
Author

bold84 commented Aug 2, 2025

#14962

An alternative PR has been proposed in parallel, maybe worth trying it before digging deeper here @bold84

In all case, really thanks for your efforts

I looked at the other PR. It doesn't solve the actual problem...
But I closed the PR anyways.

@marceldev89
Copy link

marceldev89 commented Aug 2, 2025

#14962 does make everything "work". It still prints out the tool calls and switching randomly between text + tool call, XML and JSON but I guess that's just the model and/or quant being weird.

2025-08-02-123430_1513x1227_scrot

@marceldev89
Copy link

@bold84 Thanks for the effort! Hopefully your XML work turns out to be helpful as well eventually. 😊

@bold84
Copy link
Author

bold84 commented Aug 2, 2025

@bold84 Thanks for the effort! Hopefully your XML work turns out to be helpful as well eventually. 😊

@marceldev89

Using the Hermes template, on which the model wasn't trained, makes everything work. The question is how well.
I believe there's an extremely good reason why the Qwen team (very smart people) has implemented a custom tool call parser. 😊
I implemented an XML parser (so there's no need to link external libs and no need to rely on regex) to replicate the custom tool parser by Qwen.

See: https://huggingface.co/Qwen/Qwen3-Coder-30B-A3B-Instruct/blob/main/qwen3coder_tool_parser.py

If you benchmark both templates, I would not be surprised if you would see lower performance with the Hermes template.

@marceldev89
Copy link

I tried merging master/#14962 with this PR but it's back to swallowing stuff after the #include bit unfortunately.

@bold84
Copy link
Author

bold84 commented Aug 2, 2025

I have a few more changes i haven't pushed yet.

But one thing is sure, the 30B model isn't strong with tool calls when there's 30k+ tokens in the context window.

@marceldev89
Copy link

marceldev89 commented Aug 2, 2025

non-streaming XML parser

Could this be the issue with the swallowing? Like it's parsing stuff and then the #include bit triggers an early exit or whatever. Both qwen-code and opencode stream (couldn't find an option to turn off streaming). Unless I'm misunderstanding what a "non-streaming" parser means. 😬

@marceldev89
Copy link

It's definitely something about #include < that trips the model up even for a simple hello world program. Python and JS seem to work fine-ish (with this PR) besides it never finishing due to infinite number generation for a timeout and the model just being weak-ish right now.

@bold84
Copy link
Author

bold84 commented Aug 2, 2025

I used the model with vllm a bit more, FP8 quant and Qwen's python tool parser. With crush and opencode.
I was eventually able to reproduce the exact same symptoms, which now leads me to be more confident that my implementation is correct. The ggufs are just more likely to mess up.
You can also run the test script I added in the comments up there and you will see it works flawlessly.
The more stuff is in the context window, the less likely tool calls succeed.

And as you can see, it's tricky to debug this.

This is the main reason I decided to close this PR, there's no real value in it, if Qwen3-Coder 30B A3B isn't capable enough.
This might change if Qwen releases a 32B version. In such case I will test immediately and clean up the PR.

@marceldev89
Copy link

I'm just hoping for a significant update or fix from Unsloth and/or Qwen. The non-coder non-thinking 2507 30B seemed to work fine for my small snake game in C and ncursus test.

@marceldev89
Copy link

marceldev89 commented Sep 12, 2025

@bold84 How do you feel about putting this up for a merge? The discussion at #15703 has pretty much stalled and there's seemingly no progress with implementing the "better" way. Maybe just update the template in this PR to satisfy @ggerganov 's requirements, remove the (obsolete) disclaimers about parameters and be done with it?

@marceldev89
Copy link

marceldev89 commented Sep 12, 2025

Using the upstream template from https://huggingface.co/Qwen/Qwen3-Coder-30B-A3B-Instruct/blob/main/chat_template.jinja and the upstream recommended parameters work fine.

./llama-server
    --model /home/marcel/models/Qwen3-Coder-30B-A3B-Instruct-UD-Q4_K_XL.gguf
    --alias qwen3-coder-30b-a3b-instruct
    --threads 8
    --ctx-size 32768
    --n-gpu-layers 99
    -ot "(11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32|33|34|35|36|37|38|39|40|41|42|43|44|45|46|47).ffn_.*_exps.=CPU"
    --temp 0.7
    --min-p 0.0
    --top-p 0.8
    --top-k 20
    --repeat-penalty 1.05
    --flash-attn on
    --cache-type-k q8_0
    --cache-type-v q8_0
    --jinja
    --chat-template-file ~/downloads/qwen3_coder_chat_template.jinja
    --no-mmap
20250912_132411_flameshot

@jmagder
Copy link

jmagder commented Sep 12, 2025

Using the upstream template from https://huggingface.co/Qwen/Qwen3-Coder-30B-A3B-Instruct/blob/main/chat_template.jinja and the upstream recommended parameters work fine.

On the contrary, I tried with the jinja chat template and the latest llama.cpp master branch and it did NOT work for me. Switching back to this branch and it working fine again.

@marceldev89
Copy link

On the contrary, I tried with the jinja chat template and the latest llama.cpp master branch and it did NOT work for me. Switching back to this branch and it working fine again.

Well yes, I meant with this PR. There were concerns about the updated upstream template with this PR.

@bold84
Copy link
Author

bold84 commented Sep 17, 2025

I will close this PR.

Feel free to create a new PR based on the code.
Be aware that Qwen has changed chat template and tool call parser in the meanwhile.

@bold84 bold84 closed this Sep 17, 2025
@jmagder
Copy link

jmagder commented Sep 17, 2025

Darn, I've been using this branch while eagerly feeding my OCD refreshing the discussion thread at #15703 which unfortunately is two weeks stale. The existing master llama.cpp doesn't work even with the new template. Were there any side discussions about standardizing XML Tool Call? If not, then I agree with @marceldev89 about merging the branch.

@marceldev89
Copy link

Saaaad. Like I said in a previous comment, the updated template works fine with this PR.

@bold84 bold84 reopened this Sep 17, 2025
@bold84
Copy link
Author

bold84 commented Sep 17, 2025

Fine.. I will put it up for merge, but I won't be fixing issues. :-)
@marceldev89 will you take over?

@marceldev89
Copy link

Fine.. I will put it up for merge, but I won't be fixing issues. :-)
@marceldev89 will you take over?

Yes that's alright. If anything pops up then I'll try to keep up with it. Thanks 🙏

@bold84 bold84 marked this pull request as ready for review September 17, 2025 22:44
@bold84
Copy link
Author

bold84 commented Sep 17, 2025

Darn, I've been using this branch while eagerly feeding my OCD refreshing the discussion thread at #15703 which unfortunately is two weeks stale. The existing master llama.cpp doesn't work even with the new template. Were there any side discussions about standardizing XML Tool Call? If not, then I agree with @marceldev89 about merging the branch.

Regarding #15703:
It's quite a big task to actually do this properly and I'm not sure if the maintainers would be happy with such a large change or coexisting paths.

@marceldev89
Copy link

marceldev89 commented Sep 18, 2025

Synced the PR with master and the bundled template with upstream.

@ggerganov This works flawlessly with the upstream recommended parameters and template (disregard the disclaimers in the PR). Would be nice to get this reviewed and merged in. 😊

./build/bin/llama-server \
--model /home/marcel/models/Qwen3-Coder-30B-A3B-Instruct-UD-Q4_K_XL.gguf \
--alias qwen3-coder-30b-a3b-instruct \
--threads 8 \
--ctx-size 32768 \
--n-gpu-layers 99 \
-ot "(11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32|33|34|35|36|37|38|39|40|41|42|43|44|45|46|47).ffn_.*_exps.=CPU" \
--temp 0.7 \
--min-p 0.0 \
--top-p 0.8 \
--top-k 20 \
--repeat-penalty 1.05 \
--flash-attn on \
--cache-type-k q8_0 \
--cache-type-v q8_0 \
--jinja \
--chat-template-file ./models/templates/Qwen3-Coder.jinja \
--no-mmap
20250918_180614_flameshot

@freegheist
Copy link

i'll give my 2-cents as a user here...

Ofc a base XMLToolCallParser is the clean and extensible solution for the codebase.

But Qwen Coder is a major usecase right now, and Llama.cpp is one of the main backends... if its going to be a long delay to get this working correctly (which looks like it is) then why not patch the working solution above a a stop gap. and unpatch it if and when the clean solution materializes, that way from user perspective its the most accesible and useful

thanks

@ggerganov ggerganov requested a review from ochafik September 23, 2025 06:37
@ggerganov
Copy link
Member

Let's see if @ochafik will have some capacity to chime in on the change.

In the meantime, we should see if anyone would be interested in "adopting" the chat implementation in libcommon to help maintain it going forward. It is a bit over my head atm, so it will take me some time to get familiar with it. Would prefer if there is a collaborator who can help with this part of the codebase.

@marceldev89 marceldev89 requested a review from ggerganov as a code owner October 2, 2025 18:52
@marceldev89
Copy link

@ggerganov whoops, seems like merging master into this triggered an auto review request

@Xenograph
Copy link

Xenograph commented Oct 8, 2025

Using this branch with latest jinja and unsloth/Qwen3-Coder-30B-A3B-Instruct-GGUF:Q4_K_X, things generally seem to work, but my llama-server frequently crashes with the following

slot update_slots: id  0 | task 13680 | prompt processing progress, n_past = 31253, n_tokens = 2048, progress = 0.767085
slot update_slots: id  0 | task 13680 | kv cache rm [31253, end)
slot update_slots: id  0 | task 13680 | prompt processing progress, n_past = 33301, n_tokens = 2048, progress = 0.826092
slot update_slots: id  0 | task 13680 | kv cache rm [33301, end)
slot update_slots: id  0 | task 13680 | prompt processing progress, n_past = 34708, n_tokens = 1407, progress = 0.866630
slot update_slots: id  0 | task 13680 | prompt done, n_past = 34708, n_tokens = 1407
terminate called after throwing an instance of 'std::runtime_error'
  what():  Unexpected empty grammar stack after accepting piece: <function=
zsh: IOT instruction (core dumped)  ./build/bin/llama-server -hf unsloth/Qwen3-Coder-30B-A3B-Instruct-GGUF:Q4_K_X

I'm using qwen-code CLI, in case that matters at all.

Here is my start command for llama-server:

./build/bin/llama-server \
-hf unsloth/Qwen3-Coder-30B-A3B-Instruct-GGUF:Q4_K_XL \
--alias qwen3-coder-30b-a3b-instruct \
--threads 8 \
--ctx-size 262144 \
--n-gpu-layers 99 \
--temp 0.7 \
--min-p 0.0 \
--top-p 0.8 \
--top-k 20 \
--repeat-penalty 1.05 \
--flash-attn on \
--cache-type-k q8_0 \
--cache-type-v q8_0 \
--jinja \
--chat-template-file ./qwen.jinja \
--no-mmap

GPU is RTX 5090

@marceldev89
Copy link

@Xenograph I haven't experienced any crashes at all. Maybe try without the --chat-template-file? The template embedded in the Unsloth GGUF works fine.

@Xenograph
Copy link

@Xenograph I haven't experienced any crashes at all. Maybe try without the --chat-template-file? The template embedded in the Unsloth GGUF works fine.

That might've been it, no crashes so far.

@Xenograph
Copy link

Spoke too soon, it took awhile but I eventually got another crash with the same message. This time with standard jinja.

❯ ./build/bin/llama-server \
-hf unsloth/Qwen3-Coder-30B-A3B-Instruct-GGUF:Q4_K_XL \
--alias qwen3-coder-30b-a3b-instruct \
--threads 8 \
--ctx-size 262144 \
--n-gpu-layers 99 \
--temp 0.7 \
--min-p 0.0 \
--top-p 0.8 \
--top-k 20 \
--repeat-penalty 1.05 \
--flash-attn on \
--cache-type-k q8_0 \
--cache-type-v q8_0 \
--jinja \
--no-mmap

@CHNtentes
Copy link

Hi, I also experienced crashes with the latest commit. Weirdly, there's no error message at all. Is there any debug option?

My command:

.\llama-server.exe -m D:\Qwen3-Coder-30B-A3B-Instruct-UD-Q4_K_XL.gguf -c 40960 --port 9999 --device CUDA0 -ngl 99 --temp 0.7 --min-p 0.0 --top-p 0.8 --top-k 20 --repeat-penalty 1.05 -ctk q8_0 -ctv q8_0 --alias local --jinja -ub 2048 -b 2048 -fa on --n-cpu-moe 33 --chat-template-file D:\chat_template.jinja -t 8

The error shown in qwen-code:

✦ <function
✕ [API Error: terminated]

The output from llama-server:

srv  params_from_: Chat format: Qwen3 Coder XML
slot get_availabl: id  0 | task -1 | selected slot by LRU, t_last = -1
slot launch_slot_: id  0 | task 0 | processing task
slot update_slots: id  0 | task 0 | new prompt, n_ctx_slot = 40960, n_keep = 0, n_prompt_tokens = 12152
slot update_slots: id  0 | task 0 | kv cache rm [0, end)
slot update_slots: id  0 | task 0 | prompt processing progress, n_past = 2048, n_tokens = 2048, progress = 0.168532
slot update_slots: id  0 | task 0 | kv cache rm [2048, end)
slot update_slots: id  0 | task 0 | prompt processing progress, n_past = 4096, n_tokens = 2048, progress = 0.337064
slot update_slots: id  0 | task 0 | kv cache rm [4096, end)
slot update_slots: id  0 | task 0 | prompt processing progress, n_past = 6144, n_tokens = 2048, progress = 0.505596
slot update_slots: id  0 | task 0 | kv cache rm [6144, end)
slot update_slots: id  0 | task 0 | prompt processing progress, n_past = 8192, n_tokens = 2048, progress = 0.674128
slot update_slots: id  0 | task 0 | kv cache rm [8192, end)
slot update_slots: id  0 | task 0 | prompt processing progress, n_past = 10240, n_tokens = 2048, progress = 0.842660
slot update_slots: id  0 | task 0 | kv cache rm [10240, end)
slot update_slots: id  0 | task 0 | prompt processing progress, n_past = 12152, n_tokens = 1912, progress = 1.000000
slot update_slots: id  0 | task 0 | prompt done, n_past = 12152, n_tokens = 1912

And then it just crashed...

@marceldev89
Copy link

marceldev89 commented Oct 9, 2025

I just tried it with qwen-code and it's working fine. Maybe check the sha256sum of the GGUF? 2841aa314d916434860cfb8990347528dcdfe5c350dbcb9d1461dbee88ff2533 should be a latest one.

qwen-code output
██╗       ██████╗ ██╗    ██╗███████╗███╗   ██╗
╚██╗     ██╔═══██╗██║    ██║██╔════╝████╗  ██║
 ╚██╗    ██║   ██║██║ █╗ ██║█████╗  ██╔██╗ ██║
 ██╔╝    ██║▄▄ ██║██║███╗██║██╔══╝  ██║╚██╗██║
██╔╝     ╚██████╔╝╚███╔███╔╝███████╗██║ ╚████║
╚═╝       ╚══▀▀═╝  ╚══╝╚══╝ ╚══════╝╚═╝  ╚═══╝

Tips for getting started:
1. Ask questions, edit files, or run commands.
2. Be specific for the best results.
3. Create QWEN.md files to customize your interactions with Qwen Code.
4. /help for more information.

╭─────────────────────────────────────────────────────────────────────────────╮
│  > Write a hello world program in C. Also create a Makefile and README.md.  │
╰─────────────────────────────────────────────────────────────────────────────╯

✦ I'll help you create a simple "Hello, World!" program in C along with a Makefile and README.md file.

  First, let me check if there are any existing files in the directory:

 ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
 │ ✓  ReadFolder .                                                                                                    │
 │                                                                                                                    │
 │    Directory is empty.                                                                                             │
 ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
✦ I'll create a simple "Hello, World!" program in C with a Makefile and README.md file.

  First, let me write the C program:

 ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
 │ ✓  WriteFile Writing to main.c                                                                                     │
 │                                                                                                                    │
 │    1 #include <stdio.h>                                                                                            │
 │    2                                                                                                               │
 │    3 int main() {                                                                                                  │
 │    4     printf("Hello, World!\n");                                                                                │
 │    5     return 0;                                                                                                 │
 │    6 }                                                                                                             │
 ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
✦ Now I'll create the Makefile:

 ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
 │ ✓  WriteFile Writing to Makefile                                                                                   │
 │                                                                                                                    │
 │     1 CC = gcc                                                                                                     │
 │     2 CFLAGS = -Wall -Wextra -std=c99                                                                              │
 │     3                                                                                                              │
 │     4 hello-world: main.c                                                                                          │
 │     5        $CC) $(CFLAGS) -o hello-world main.c                                                                        │
 │     6                                                                                                              │
 │     7 clean:                                                                                                       │
 │     8 rm -f hello-world                                                                                            │
 │     9                                                                                                              │
 │    10 .PHONY: clean                                                                                                │
 ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
✦ Now I'll create the README.md file:

 ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
 │ ✓  WriteFile Writing to README.md                                                                                  │
 │                                                                                                                    │
 │     1 # Hello World in C                                                                                           │
 │     2                                                                                                              │
 │     3 A simple "Hello, World!" program written in C.                                                               │
 │     4                                                                                                              │
 │     5 ## Building                                                                                                  │
 │     6                                                                                                              │
 │     7 To compile the program, run:                                                                                 │
 │     8                                                                                                              │
 │     9 ```bash                                                                                                      │
 │    10 make                                                                                                         │
 │    11 ```                                                                                                          │
 │    12                                                                                                              │
 │    13 This will generate an executable named `hello-world`.                                                        │
 │    14                                                                                                              │
 │    15 ## Running                                                                                                   │
 │    16                                                                                                              │
 │    17 After building, you can run the program with:                                                                │
 │    18                                                                                                              │
 │    19 ```bash                                                                                                      │
 │    20 ./hello-world                                                                                                │
 │    21 ```                                                                                                          │
 │    22                                                                                                              │
 │    23 ## Cleaning                                                                                                  │
 │    24                                                                                                              │
 │    25 To remove the compiled executable, run:                                                                      │
 │    26                                                                                                              │
 │    27 ```bash                                                                                                      │
 │    28 make clean                                                                                                   │
 │    29 ```                                                                                                          │
 ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
✦ Let me build and test the program to make sure everything works correctly:

 ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
 │ ✓  Shell cd /home/marcel/projects/helloworld && make                                                               │
 │                                                                                                                    │
 │    gcc -Wall -Wextra -std=c99 -o hello-world main.c                                                                │
 ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
✦ Now let's run the program to verify it works correctly:

 ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
 │ ✓  Shell cd /home/marcel/projects/helloworld && ./hello-world                                                      │
 │                                                                                                                    │
 │    Hello, World!                                                                                                   │
 ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
✦ Let me also test the clean functionality:

 ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
 │ ✓  Shell cd /home/marcel/projects/helloworld && make clean                                                         │
 │                                                                                                                    │
 │    rm -f hello-world                                                                                               │
 ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
✦ Let me verify that the executable was properly removed:

 ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
 │ ✓  Shell cd /home/marcel/projects/helloworld && ls -la                                                             │
 │                                                                                                                    │
 │    total 20                                                                                                        │
 │    drwxr-xr-x  2 marcel marcel 4096 Oct  9 13:43 .                                                                 │
 │    drwxr-xr-x 81 marcel marcel 4096 Sep 30 15:50 ..                                                                │
 │    -rw-r--r--  1 marcel marcel   79 Oct  9 13:42 main.c                                                            │
 │    -rw-r--r--  1 marcel marcel  142 Oct  9 13:42 Makefile                                                          │
 │    -rw-r--r--  1 marcel marcel  346 Oct  9 13:42 README.md                                                         │
 ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
✦ I've successfully created a complete "Hello, World!" program in C with the following files:

   1. main.c - The C source code that prints "Hello, World!"
   2. Makefile - A Makefile to compile and clean the program
   3. README.md - Documentation explaining how to build, run, and clean the program

  All files have been created in the project directory /home/marcel/projects/helloworld. The program has been built
  and tested successfully, and the clean functionality works as expected.

  The Makefile includes:
   - Compilation with gcc using standard C99
   - Warning flags for better code quality
   - A clean target to remove the compiled executable

  The README.md explains how to use the Makefile commands to build, run, and clean the program.

╭─────────────────────────────────────────────────────────╮
│  > Add some animations and stuff to make it more fancy  │
╰─────────────────────────────────────────────────────────╯

✦ I'll enhance the "Hello, World!" program with some fancy animations and visual effects to make it more interesting.

  First, I'll update the main C file to include some basic terminal animations:

 ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
 │ ✓  Edit main.c: #include <stdio.h>... => #include <stdio.h>...                                                     │
 │                                                                                                                    │
 │     1   #include <stdio.h>                                                                                         │
 │     2 + #include <stdlib.h>                                                                                        │
 │     3 + #include <string.h>                                                                                        │
 │     4 + #include <unistd.h>                                                                                        │
 │     5 + #include <time.h>                                                                                          │
 │     6                                                                                                              │
 │     7 + void printAnimatedText(const char* text) {                                                                 │
 │     8 +     int len = strlen(text);                                                                                │
 │     9 +     for (int i = 0; i < len; i++) {                                                                        │
 │    10 +         printf("%c", text[i]);                                                                             │
 │    11 +         fflush(stdout);                                                                                    │
 │    12 +         usleep(100000); // 0.1 second delay                                                                │
 │    13 +     }                                                                                                      │
 │    14 +     printf("\n");                                                                                          │
 │    15 + }                                                                                                          │
 │    16 +                                                                                                            │
 │    17 + void printLoadingAnimation(int duration) {                                                                 │
 │    18 +     const char* loadingChars[] = {"|", "/", "-", "\\"};                                                    │
 │    19 +     int numChars = sizeof(loadingChars) / sizeof(loadingChars[0]);                                         │
 │    20 +                                                                                                            │
 │    21 +     for (int i = 0; i < duration * 10; i++) {                                                              │
 │    22 +         printf("\r%s", loadingChars[i % numChars]);                                                        │
 │    23 +         fflush(stdout);                                                                                    │
 │    24 +         usleep(100000); // 0.1 second delay                                                                │
 │    25 +     }                                                                                                      │
 │    26 +     printf("\r");                                                                                          │
 │    27 + }                                                                                                          │
 │    28 +                                                                                                            │
 │    29 + void printBoxedText(const char* text) {                                                                    │
 │    30 +     int len = strlen(text);                                                                                │
 │    31 +     printf("+");                                                                                           │
 │    32 +     for (int i = 0; i < len + 2; i++) printf("-");                                                         │
 │    33 +     printf("+\n");                                                                                         │
 │    34 +                                                                                                            │
 │    35 +     printf("| %s |\n", text);                                                                              │
 │    36 +                                                                                                            │
 │    37 +     printf("+");                                                                                           │
 │    38 +     for (int i = 0; i < len + 2; i++) printf("-");                                                         │
 │    39 +     printf("+\n");                                                                                         │
 │    40 + }                                                                                                          │
 │    41 +                                                                                                            │
 │    42   int main() {                                                                                               │
 │     4 -     printf("Hello, World!\n");                                                                             │
 │    ════════════════════════════════════════════════════════════════════════════════════════════════════            │
 │    43 +     // Initialize random seed                                                                              │
 │    44 +     srand(time(NULL));                                                                                     │
 │    45 +                                                                                                            │
 │    46 +     printf("\n");                                                                                          │
 │    47 +     printAnimatedText("Welcome to the fancy Hello, World! program!");                                      │
 │    48 +     printf("\n");                                                                                          │
 │    49 +                                                                                                            │
 │    50 +     printLoadingAnimation(3);                                                                              │
 │    51 +     printf("Starting animation sequence...\n\n");                                                          │
 │    52 +                                                                                                            │
 │    53 +     // Create a simple animation with colors (if supported)                                                │
 │    54 +     printf("\033[1;32m"); // Green color                                                                   │
 │    55 +     printBoxedText("Hello, World!");                                                                       │
 │    56 +     printf("\033[0m"); // Reset color                                                                      │
 │    57 +                                                                                                            │
 │    58 +     printf("\n");                                                                                          │
 │    59 +     printAnimatedText("The program will now exit...");                                                     │
 │    60 +                                                                                                            │
 │    61       return 0;                                                                                              │
 │    62   }                                                                                                          │
 ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
✦ Now I'll update the Makefile to ensure it compiles with the necessary flags for color support:

 ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
 │ x  Edit {"file_path":"/home/marcel/projects/helloworld/Makefile","old_string":"CC = gcc\nCFLAGS = -Wall -Wextra -… │
 │                                                                                                                    │
 │    No changes to apply. The old_string and new_string are identical in file:                                       │
 │    /home/marcel/projects/helloworld/Makefile                                                                       │
 ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
✦ The Makefile is already set up correctly for our needs. Let's build and test the enhanced program:

 ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
 │ ✓  Shell cd /home/marcel/projects/helloworld && make                                                               │
 │                                                                                                                    │
 │    gcc -Wall -Wextra -std=c99 -o hello-world main.c                                                                │
 │    main.c: In function ‘printAnimatedText’:                                                                        │
 │    main.c:12:9: error: implicit declaration of function ‘usleep’; did you mean ‘sleep’?                            │
 │    [-Wimplicit-function-declaration]                                                                               │
 │       12 |         usleep(100000); // 0.1 second delay                                                             │
 │          |         ^~~~~~                                                                                          │
 │          |         sleep                                                                                           │
 │    make: *** [Makefile:5: hello-world] Error 1                                                                     │
 ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
✦ I need to include the proper header for usleep and add the necessary feature test macros. Let me fix this:

 ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
 │ ✓  Edit main.c: #include <stdio.h>... => #define _GNU_SOURCE...                                                    │
 │                                                                                                                    │
 │     1 + #define _GNU_SOURCE                                                                                        │
 │     2   #include <stdio.h>                                                                                         │
 │     3   #include <stdlib.h>                                                                                        │
 │     4   #include <string.h>                                                                                        │
 │     5   #include <unistd.h>                                                                                        │
 │     6   #include <time.h>                                                                                          │
 │     7 + #include <sys/time.h>                                                                                      │
 │     8                                                                                                              │
 │     9   void printAnimatedText(const char* text) {                                                                 │
 │    10       int len = strlen(text);                                                                                │
 ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
✦ Now let's build and test the enhanced program:

 ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
 │ ✓  Shell cd /home/marcel/projects/helloworld && make                                                               │
 │                                                                                                                    │
 │    gcc -Wall -Wextra -std=c99 -o hello-world main.c                                                                │
 ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
✦ Great! Now let's run the enhanced program to see the animations:

 ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
 │ ✓  Shell cd /home/marcel/projects/helloworld && ./hello-world                                                      │
 │                                                                                                                    │
 │    Welcome to the fancy Hello, World! program!                                                                     │
 │                                                                                                                    │
Starting animation sequence...                     │
 │                                                                                                                    │
 │    +---------------+                                                                                               │
 │    | Hello, World! |                                                                                               │
 │    +---------------+                                                                                               │
 │                                                                                                                    │
 │    The program will now exit...                                                                                    │
 ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
✦ Perfect! The enhanced "Hello, World!" program now includes:

   1. Animated text printing - characters appear one by one
   2. Loading animation - a rotating character that shows progress
   3. Boxed text display - the "Hello, World!" message is displayed in a decorative box
   4. Color output - the boxed text appears in green

  All these animations work correctly when running the program in a terminal that supports ANSI escape sequences.

  Let me also update the README.md file to document these enhancements:

 ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
 │ ✓  Edit README.md: # Hello World in C... => # Fancy Hello World in C...                                            │
 │                                                                                                                    │
 │     1 - # Hello World in C                                                                                         │
 │     1 + # Fancy Hello World in C                                                                                   │
 │     2                                                                                                              │
 │     3 - A simple "Hello, World!" program written in C.                                                             │
 │     3 + A "Hello, World!" program written in C with fancy animations and visual effects.                           │
 │     4                                                                                                              │
 │     5 + ## Features                                                                                                │
 │     6 +                                                                                                            │
 │     7 + - Animated text printing (characters appear one by one)                                                    │
 │     8 + - Loading animation (rotating character showing progress)                                                  │
 │     9 + - Boxed text display for the main message                                                                  │
 │    10 + - Color output (green text for the boxed message)                                                          │
 │    11 +                                                                                                            │
 │    12   ## Building                                                                                                │
 │    13                                                                                                              │
 │    14   To compile the program, run:                                                                               │
 ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
✦ I've successfully enhanced the "Hello, World!" program with several fancy animations and visual effects. Here's what
  I've added:

   1. Animated Text Printing - Characters in text appear one by one with a small delay for a typing effect
   2. Loading Animation - A rotating character (| / - \) that shows progress during startup
   3. Boxed Text Display - The "Hello, World!" message is displayed in a decorative box
   4. Color Output - The boxed text appears in green color using ANSI escape sequences

  The program still compiles and runs correctly with the updated Makefile and README.md documentation.

  All files are now in place:
   - main.c - Enhanced C source code with animations
   - Makefile - Compilation instructions (already had proper flags)
   - README.md - Updated documentation explaining the new features

  The enhanced program can be built and run using the same commands as before, but now provides a more visually
  engaging experience.


                                                                                  YOLO mode (shift + tab to cycle)
╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ >   Type your message or @path/to/file                                                                         │
╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
~/projects/helloworld           no sandbox (see /docs)             qwen3-coder-30b-a3b-instruct (96% context left)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
testing Everything test related
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Feature Request: Qwen3-Coder Tool Call Parser