- 前端: 所有界面显示、i18n 文本、组件中的品牌名称 - 后端: 服务层、设置默认值、邮件模板、安装向导 - 数据库: 迁移脚本注释 - 保持功能完全一致,仅更改品牌名称 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
180 lines
5.0 KiB
Go
180 lines
5.0 KiB
Go
package antigravity
|
||
|
||
import (
|
||
"encoding/json"
|
||
"testing"
|
||
)
|
||
|
||
// TestBuildParts_ThinkingBlockWithoutSignature 测试thinking block无signature时的处理
|
||
func TestBuildParts_ThinkingBlockWithoutSignature(t *testing.T) {
|
||
tests := []struct {
|
||
name string
|
||
content string
|
||
allowDummyThought bool
|
||
expectedParts int
|
||
description string
|
||
}{
|
||
{
|
||
name: "Claude model - skip thinking block without signature",
|
||
content: `[
|
||
{"type": "text", "text": "Hello"},
|
||
{"type": "thinking", "thinking": "Let me think...", "signature": ""},
|
||
{"type": "text", "text": "World"}
|
||
]`,
|
||
allowDummyThought: false,
|
||
expectedParts: 2, // 只有两个text block
|
||
description: "Claude模型应该跳过无signature的thinking block",
|
||
},
|
||
{
|
||
name: "Claude model - keep thinking block with signature",
|
||
content: `[
|
||
{"type": "text", "text": "Hello"},
|
||
{"type": "thinking", "thinking": "Let me think...", "signature": "valid_sig"},
|
||
{"type": "text", "text": "World"}
|
||
]`,
|
||
allowDummyThought: false,
|
||
expectedParts: 3, // 三个block都保留
|
||
description: "Claude模型应该保留有signature的thinking block",
|
||
},
|
||
{
|
||
name: "Gemini model - use dummy signature",
|
||
content: `[
|
||
{"type": "text", "text": "Hello"},
|
||
{"type": "thinking", "thinking": "Let me think...", "signature": ""},
|
||
{"type": "text", "text": "World"}
|
||
]`,
|
||
allowDummyThought: true,
|
||
expectedParts: 3, // 三个block都保留,thinking使用dummy signature
|
||
description: "Gemini模型应该为无signature的thinking block使用dummy signature",
|
||
},
|
||
}
|
||
|
||
for _, tt := range tests {
|
||
t.Run(tt.name, func(t *testing.T) {
|
||
toolIDToName := make(map[string]string)
|
||
parts, err := buildParts(json.RawMessage(tt.content), toolIDToName, tt.allowDummyThought)
|
||
|
||
if err != nil {
|
||
t.Fatalf("buildParts() error = %v", err)
|
||
}
|
||
|
||
if len(parts) != tt.expectedParts {
|
||
t.Errorf("%s: got %d parts, want %d parts", tt.description, len(parts), tt.expectedParts)
|
||
}
|
||
})
|
||
}
|
||
}
|
||
|
||
// TestBuildTools_CustomTypeTools 测试custom类型工具转换
|
||
func TestBuildTools_CustomTypeTools(t *testing.T) {
|
||
tests := []struct {
|
||
name string
|
||
tools []ClaudeTool
|
||
expectedLen int
|
||
description string
|
||
}{
|
||
{
|
||
name: "Standard tool format",
|
||
tools: []ClaudeTool{
|
||
{
|
||
Name: "get_weather",
|
||
Description: "Get weather information",
|
||
InputSchema: map[string]any{
|
||
"type": "object",
|
||
"properties": map[string]any{
|
||
"location": map[string]any{"type": "string"},
|
||
},
|
||
},
|
||
},
|
||
},
|
||
expectedLen: 1,
|
||
description: "标准工具格式应该正常转换",
|
||
},
|
||
{
|
||
name: "Custom type tool (MCP format)",
|
||
tools: []ClaudeTool{
|
||
{
|
||
Type: "custom",
|
||
Name: "mcp_tool",
|
||
Custom: &ClaudeCustomToolSpec{
|
||
Description: "MCP tool description",
|
||
InputSchema: map[string]any{
|
||
"type": "object",
|
||
"properties": map[string]any{
|
||
"param": map[string]any{"type": "string"},
|
||
},
|
||
},
|
||
},
|
||
},
|
||
},
|
||
expectedLen: 1,
|
||
description: "Custom类型工具应该从Custom字段读取description和input_schema",
|
||
},
|
||
{
|
||
name: "Mixed standard and custom tools",
|
||
tools: []ClaudeTool{
|
||
{
|
||
Name: "standard_tool",
|
||
Description: "Standard tool",
|
||
InputSchema: map[string]any{"type": "object"},
|
||
},
|
||
{
|
||
Type: "custom",
|
||
Name: "custom_tool",
|
||
Custom: &ClaudeCustomToolSpec{
|
||
Description: "Custom tool",
|
||
InputSchema: map[string]any{"type": "object"},
|
||
},
|
||
},
|
||
},
|
||
expectedLen: 1, // 返回一个GeminiToolDeclaration,包含2个function declarations
|
||
description: "混合标准和custom工具应该都能正确转换",
|
||
},
|
||
{
|
||
name: "Invalid custom tool - nil Custom field",
|
||
tools: []ClaudeTool{
|
||
{
|
||
Type: "custom",
|
||
Name: "invalid_custom",
|
||
// Custom 为 nil
|
||
},
|
||
},
|
||
expectedLen: 0, // 应该被跳过
|
||
description: "Custom字段为nil的custom工具应该被跳过",
|
||
},
|
||
{
|
||
name: "Invalid custom tool - nil InputSchema",
|
||
tools: []ClaudeTool{
|
||
{
|
||
Type: "custom",
|
||
Name: "invalid_custom",
|
||
Custom: &ClaudeCustomToolSpec{
|
||
Description: "Invalid",
|
||
// InputSchema 为 nil
|
||
},
|
||
},
|
||
},
|
||
expectedLen: 0, // 应该被跳过
|
||
description: "InputSchema为nil的custom工具应该被跳过",
|
||
},
|
||
}
|
||
|
||
for _, tt := range tests {
|
||
t.Run(tt.name, func(t *testing.T) {
|
||
result := buildTools(tt.tools)
|
||
|
||
if len(result) != tt.expectedLen {
|
||
t.Errorf("%s: got %d tool declarations, want %d", tt.description, len(result), tt.expectedLen)
|
||
}
|
||
|
||
// 验证function declarations存在
|
||
if len(result) > 0 && result[0].FunctionDeclarations != nil {
|
||
if len(result[0].FunctionDeclarations) != len(tt.tools) {
|
||
t.Errorf("%s: got %d function declarations, want %d",
|
||
tt.description, len(result[0].FunctionDeclarations), len(tt.tools))
|
||
}
|
||
}
|
||
})
|
||
}
|
||
}
|