Merge commit '34df42f7bef5a711b2b40f5d2b6b78254def99c3' into concedo_experimental

# Conflicts:
#	README.md
#	ggml/src/ggml-hexagon/ggml-hexagon.cpp
#	ggml/src/ggml-hexagon/htp/CMakeLists.txt
#	ggml/src/ggml-hexagon/htp/act-ops.c
#	ggml/src/ggml-hexagon/htp/binary-ops.c
#	ggml/src/ggml-hexagon/htp/cpy-ops.c
#	ggml/src/ggml-hexagon/htp/get-rows-ops.c
#	ggml/src/ggml-hexagon/htp/htp-msg.h
#	ggml/src/ggml-hexagon/htp/htp-ops.h
#	ggml/src/ggml-hexagon/htp/hvx-arith.h
#	ggml/src/ggml-hexagon/htp/hvx-base.h
#	ggml/src/ggml-hexagon/htp/hvx-inverse.h
#	ggml/src/ggml-hexagon/htp/hvx-utils.h
#	ggml/src/ggml-hexagon/htp/main.c
#	ggml/src/ggml-hexagon/htp/rope-ops.c
#	ggml/src/ggml-hexagon/htp/set-rows-ops.c
#	ggml/src/ggml-hexagon/htp/softmax-ops.c
#	ggml/src/ggml-hexagon/htp/unary-ops.c
#	ggml/src/ggml-opencl/CMakeLists.txt
#	ggml/src/ggml-opencl/ggml-opencl.cpp
#	tests/test-backend-ops.cpp
#	tools/cli/cli.cpp
#	tools/server/webui/src/lib/components/app/chat/ChatScreen/ChatScreen.svelte
This commit is contained in:
Concedo
2026-03-10 22:20:04 +08:00
168 changed files with 15852 additions and 1398 deletions
@@ -809,6 +809,139 @@ def test_anthropic_vs_openai_different_response_format():
# Extended thinking tests with reasoning models
# The next two tests cover the input path (conversation history):
# Client sends thinking blocks -> convert_anthropic_to_oai -> reasoning_content -> template
def test_anthropic_thinking_history_in_count_tokens():
"""Test that interleaved thinking blocks in conversation history are not dropped during conversion."""
global server
server.jinja = True
server.chat_template_file = '../../../models/templates/Qwen-Qwen3-0.6B.jinja'
server.start()
tool = {
"name": "list_files",
"description": "List files",
"input_schema": {
"type": "object",
"properties": {"path": {"type": "string"}},
"required": ["path"]
}
}
messages_without_thinking = [
{"role": "user", "content": "Fix the bug"},
{
"role": "assistant",
"content": [
{"type": "tool_use", "id": "call_1", "name": "list_files", "input": {"path": "."}}
]
},
{
"role": "user",
"content": [
{"type": "tool_result", "tool_use_id": "call_1", "content": "main.py"}
]
},
]
messages_with_thinking = [
{"role": "user", "content": "Fix the bug"},
{
"role": "assistant",
"content": [
{"type": "thinking", "thinking": "I should check the project structure first to understand the codebase layout."},
{"type": "tool_use", "id": "call_1", "name": "list_files", "input": {"path": "."}}
]
},
{
"role": "user",
"content": [
{"type": "tool_result", "tool_use_id": "call_1", "content": "main.py"}
]
},
]
res_without = server.make_request("POST", "/v1/messages/count_tokens", data={
"model": "test",
"messages": messages_without_thinking,
"tools": [tool],
})
assert res_without.status_code == 200, f"Expected 200: {res_without.body}"
res_with = server.make_request("POST", "/v1/messages/count_tokens", data={
"model": "test",
"messages": messages_with_thinking,
"tools": [tool],
})
assert res_with.status_code == 200, f"Expected 200: {res_with.body}"
# Thinking blocks should increase the token count
assert res_with.body["input_tokens"] > res_without.body["input_tokens"], \
f"Expected more tokens with thinking ({res_with.body['input_tokens']}) than without ({res_without.body['input_tokens']})"
def test_anthropic_thinking_history_in_template():
"""Test that reasoning_content from converted interleaved thinking blocks renders in the prompt."""
global server
server.jinja = True
server.chat_template_file = '../../../models/templates/Qwen-Qwen3-0.6B.jinja'
server.start()
reasoning_1 = "I should check the project structure first."
reasoning_2 = "Now I need to read the main file."
res = server.make_request("POST", "/apply-template", data={
"messages": [
{"role": "user", "content": "Fix the bug in main.py"},
{
"role": "assistant",
"content": "",
"reasoning_content": reasoning_1,
"tool_calls": [{
"id": "call_1",
"type": "function",
"function": {"name": "list_files", "arguments": "{\"path\": \".\"}"}
}]
},
{"role": "tool", "tool_call_id": "call_1", "content": "main.py\nutils.py"},
{
"role": "assistant",
"content": "",
"reasoning_content": reasoning_2,
"tool_calls": [{
"id": "call_2",
"type": "function",
"function": {"name": "read_file", "arguments": "{\"path\": \"main.py\"}"}
}]
},
{"role": "tool", "tool_call_id": "call_2", "content": "print('hello')"},
],
"tools": [{
"type": "function",
"function": {
"name": "list_files",
"description": "List files",
"parameters": {"type": "object", "properties": {"path": {"type": "string"}}, "required": ["path"]}
}
}, {
"type": "function",
"function": {
"name": "read_file",
"description": "Read a file",
"parameters": {"type": "object", "properties": {"path": {"type": "string"}}, "required": ["path"]}
}
}],
})
assert res.status_code == 200, f"Expected 200, got {res.status_code}: {res.body}"
prompt = res.body["prompt"]
# Both reasoning_content values should be rendered in <think> tags
assert reasoning_1 in prompt, f"Expected first reasoning text in prompt: {prompt}"
assert reasoning_2 in prompt, f"Expected second reasoning text in prompt: {prompt}"
assert prompt.count("<think>") >= 2, f"Expected at least 2 <think> blocks in prompt: {prompt}"
@pytest.mark.slow
@pytest.mark.parametrize("stream", [False, True])
def test_anthropic_thinking_with_reasoning_model(stream):