Skip to content

Misc. bug: reasoning-budget stopped working #22717

Description

@wbste

Name and Version

llama-cli --version
version: 9033 (70a830911)
built with Clang 19.1.5 for Windows x86_64

Operating systems

Windows

Which llama.cpp modules do you know to be affected?

llama-server

Command line

llama-server `
  --model "D:\AI\models\unsloth\Qwen3.5-2B-GGUF\Qwen3.5-4B-Q8_0.gguf" `
  --mmproj "D:\AI\models\unsloth\Qwen3.5-2B-GGUF\mmproj-F16.gguf" `
  --temp 0.6 `
  --top-k 20 `
  --top-p 0.95 `
  --min-p 0.0 `
  --repeat-penalty 1.0 `
  --presence-penalty 0.0 `
  --reasoning-budget 100 `
  --reasoning-budget-message "Wait, I am overthinking this. I should answer now." `
  --chat-template-kwargs '{"preserve_thinking":true}'

Problem description & steps to reproduce

Only tested on a few models so far. My workflow has been running fine until this morning. When reasoning turned on I'm not seeing the reasoning budget message any longer, and seems to be replaced with something like *'/'''''/''''/'. Therefore it blasts through the budget and tends to start to loop.

Demo code, where you'll see right at the reasoning-budget threshold the characters appear:

# /// script
# dependencies = ["httpx", "openai"]
# ///

import asyncio
import base64
import logging

import httpx
from openai import AsyncOpenAI

logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s")
log = logging.getLogger(__name__)

OWNER, REPO = "ggml-org", "llama.cpp"
BASE_URL = "http://127.0.0.1:9292/v1/"
API_KEY = "local"
MODEL_NAME = "qwen3.5-2b"
USER_PROMPT = "Summarize the following in three sentences or less, no markdown. Don't preamble with you're making a summary; just do it."


async def fetch_readme(owner: str, repo: str) -> tuple[str, str]:
    headers = {
        "Accept": "application/vnd.github+json",
        "X-GitHub-Api-Version": "2022-11-28",
    }

    async with httpx.AsyncClient(timeout=30) as client:
        repo_data = (
            await client.get(
                f"https://api.github.com/repos/{owner}/{repo}", headers=headers
            )
        ).json()
        readme_resp = await client.get(
            f"https://api.github.com/repos/{owner}/{repo}/readme", headers=headers
        )

    title = repo_data.get("full_name", f"{owner}/{repo}")
    if desc := repo_data.get("description"):
        title = f"{title}{desc}"

    markdown = ""
    if readme_resp.status_code == 200:
        markdown = base64.b64decode(readme_resp.json().get("content", "")).decode(
            "utf-8", errors="replace"
        )

    return title, markdown


async def stream_summary(content: str) -> None:
    client = AsyncOpenAI(base_url=BASE_URL, api_key=API_KEY)
    thinking_chars = 0
    in_thinking = True

    print("\n--- THINKING ---", flush=True)
    stream = await client.chat.completions.create(
        model=MODEL_NAME,
        messages=[{"role": "user", "content": f"{USER_PROMPT}\n\nContent:\n{content}"}],
        extra_body={"chat_template_kwargs": {"enable_thinking": True}},
        stream=True,
    )
    async for chunk in stream:
        if not chunk.choices:
            continue
        delta = chunk.choices[0].delta
        if reasoning := getattr(delta, "reasoning_content", None):
            thinking_chars += len(reasoning)
            print(reasoning, end="", flush=True)
        if answer := delta.content:
            if in_thinking:
                in_thinking = False
                print(
                    f"\n--- ANSWER (thinking ~{thinking_chars // 4} tokens) ---",
                    flush=True,
                )
            print(answer, end="", flush=True)

    print("\n--- END STREAM ---", flush=True)


async def main() -> None:
    log.info("Fetching %s/%s README...", OWNER, REPO)
    title, content = await fetch_readme(OWNER, REPO)
    log.info("Title: %s", title)
    try:
        await stream_summary(content)
    except Exception as e:
        log.error("Error: %s", e)


asyncio.run(main())

First Bad Commit

Around the b9018 release

Relevant log output

Logs

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions