Files
CLIProxyAPI/internal/thinking/provider/claude/apply_test.go
이대희 c548c5d49f Fixes Claude API thinking block requirement
Addresses a Claude API requirement where assistant messages with tool use must have a thinking block when thinking is enabled.

This commit injects an empty thinking block into assistant messages that include tool use but lack a thinking block. This ensures compatibility with the Claude API when the thinking feature is enabled.
2026-02-02 14:04:29 +09:00

188 lines
4.2 KiB
Go

package claude
import (
"testing"
"github.com/router-for-me/CLIProxyAPI/v6/internal/thinking"
"github.com/tidwall/gjson"
)
func TestInjectThinkingBlockForToolUse(t *testing.T) {
tests := []struct {
name string
input string
expected string
}{
{
name: "assistant with tool_use but no thinking - should inject thinking",
input: `{
"model": "kimi-k2.5",
"messages": [
{
"role": "assistant",
"content": [
{"type": "text", "text": "Let me use a tool"},
{"type": "tool_use", "id": "tool_1", "name": "test_tool", "input": {}}
]
}
]
}`,
expected: "thinking",
},
{
name: "assistant with tool_use and thinking - should not modify",
input: `{
"model": "kimi-k2.5",
"messages": [
{
"role": "assistant",
"content": [
{"type": "thinking", "thinking": "I need to use a tool"},
{"type": "tool_use", "id": "tool_1", "name": "test_tool", "input": {}}
]
}
]
}`,
expected: "thinking",
},
{
name: "user message with tool_use - should not modify",
input: `{
"model": "kimi-k2.5",
"messages": [
{
"role": "user",
"content": [
{"type": "tool_result", "tool_use_id": "tool_1", "content": "result"}
]
}
]
}`,
expected: "",
},
{
name: "assistant without tool_use - should not modify",
input: `{
"model": "kimi-k2.5",
"messages": [
{
"role": "assistant",
"content": [
{"type": "text", "text": "Hello!"}
]
}
]
}`,
expected: "",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := injectThinkingBlockForToolUse([]byte(tt.input))
// Check if thinking block exists in assistant messages with tool_use
messages := gjson.GetBytes(result, "messages")
if !messages.IsArray() {
t.Fatal("messages is not an array")
}
for _, msg := range messages.Array() {
if msg.Get("role").String() == "assistant" {
content := msg.Get("content")
if !content.IsArray() {
continue
}
hasToolUse := false
hasThinking := false
for _, part := range content.Array() {
partType := part.Get("type").String()
if partType == "tool_use" {
hasToolUse = true
}
if partType == "thinking" {
hasThinking = true
}
}
if hasToolUse && tt.expected == "thinking" && !hasThinking {
t.Errorf("Expected thinking block in assistant message with tool_use, but not found")
}
}
}
})
}
}
func TestApplyCompatibleClaude(t *testing.T) {
tests := []struct {
name string
input string
config thinking.ThinkingConfig
expectThinking bool
}{
{
name: "thinking enabled with tool_use - should inject thinking block",
input: `{
"model": "kimi-k2.5",
"messages": [
{
"role": "assistant",
"content": [
{"type": "tool_use", "id": "tool_1", "name": "test_tool", "input": {}}
]
}
]
}`,
config: thinking.ThinkingConfig{
Mode: thinking.ModeBudget,
Budget: 4000,
},
expectThinking: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result, err := applyCompatibleClaude([]byte(tt.input), tt.config)
if err != nil {
t.Fatalf("applyCompatibleClaude failed: %v", err)
}
// Check if thinking.type is enabled
thinkingType := gjson.GetBytes(result, "thinking.type").String()
if thinkingType != "enabled" {
t.Errorf("Expected thinking.type=enabled, got %s", thinkingType)
}
// Check if thinking block is injected
messages := gjson.GetBytes(result, "messages")
if !messages.IsArray() {
t.Fatal("messages is not an array")
}
for _, msg := range messages.Array() {
if msg.Get("role").String() == "assistant" {
content := msg.Get("content")
if !content.IsArray() {
continue
}
hasThinking := false
for _, part := range content.Array() {
if part.Get("type").String() == "thinking" {
hasThinking = true
break
}
}
if tt.expectThinking && !hasThinking {
t.Errorf("Expected thinking block in assistant message, but not found. Result: %s", string(result))
}
}
}
})
}
}