Merge branch 'main' into test
This commit is contained in:
@@ -71,6 +71,12 @@ var DefaultModels = []Model{
|
|||||||
DisplayName: "Claude Opus 4.5",
|
DisplayName: "Claude Opus 4.5",
|
||||||
CreatedAt: "2025-11-01T00:00:00Z",
|
CreatedAt: "2025-11-01T00:00:00Z",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
ID: "claude-opus-4-6",
|
||||||
|
Type: "model",
|
||||||
|
DisplayName: "Claude Opus 4.6",
|
||||||
|
CreatedAt: "2026-02-06T00:00:00Z",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
ID: "claude-sonnet-4-5-20250929",
|
ID: "claude-sonnet-4-5-20250929",
|
||||||
Type: "model",
|
Type: "model",
|
||||||
|
|||||||
@@ -1089,8 +1089,9 @@ func (r *accountRepository) UpdateExtra(ctx context.Context, id int64, updates m
|
|||||||
result, err := client.ExecContext(
|
result, err := client.ExecContext(
|
||||||
ctx,
|
ctx,
|
||||||
"UPDATE accounts SET extra = COALESCE(extra, '{}'::jsonb) || $1::jsonb, updated_at = NOW() WHERE id = $2 AND deleted_at IS NULL",
|
"UPDATE accounts SET extra = COALESCE(extra, '{}'::jsonb) || $1::jsonb, updated_at = NOW() WHERE id = $2 AND deleted_at IS NULL",
|
||||||
payload, id,
|
string(payload), id,
|
||||||
)
|
)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -102,8 +102,10 @@ func TestStreamingReconcile_MessageStart(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 验证 cache_read_input_tokens 已被填充
|
// 验证 cache_read_input_tokens 已被填充
|
||||||
msg := event["message"].(map[string]any)
|
msg, ok := event["message"].(map[string]any)
|
||||||
usage := msg["usage"].(map[string]any)
|
require.True(t, ok)
|
||||||
|
usage, ok := msg["usage"].(map[string]any)
|
||||||
|
require.True(t, ok)
|
||||||
assert.Equal(t, float64(23), usage["cache_read_input_tokens"])
|
assert.Equal(t, float64(23), usage["cache_read_input_tokens"])
|
||||||
|
|
||||||
// 验证重新序列化后 JSON 也包含正确值
|
// 验证重新序列化后 JSON 也包含正确值
|
||||||
@@ -134,8 +136,10 @@ func TestStreamingReconcile_MessageStart_NativeClaude(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
msg := event["message"].(map[string]any)
|
msg, ok := event["message"].(map[string]any)
|
||||||
usage := msg["usage"].(map[string]any)
|
require.True(t, ok)
|
||||||
|
usage, ok := msg["usage"].(map[string]any)
|
||||||
|
require.True(t, ok)
|
||||||
assert.Equal(t, float64(30), usage["cache_read_input_tokens"])
|
assert.Equal(t, float64(30), usage["cache_read_input_tokens"])
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,11 +163,9 @@ func TestStreamingReconcile_MessageDelta(t *testing.T) {
|
|||||||
require.Equal(t, "message_delta", eventType)
|
require.Equal(t, "message_delta", eventType)
|
||||||
|
|
||||||
// 模拟 processSSEEvent 中的 reconcile 逻辑
|
// 模拟 processSSEEvent 中的 reconcile 逻辑
|
||||||
if u, ok := event["usage"].(map[string]any); ok {
|
usage, ok := event["usage"].(map[string]any)
|
||||||
reconcileCachedTokens(u)
|
require.True(t, ok)
|
||||||
}
|
reconcileCachedTokens(usage)
|
||||||
|
|
||||||
usage := event["usage"].(map[string]any)
|
|
||||||
assert.Equal(t, float64(15), usage["cache_read_input_tokens"])
|
assert.Equal(t, float64(15), usage["cache_read_input_tokens"])
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -179,11 +181,9 @@ func TestStreamingReconcile_MessageDelta_NativeClaude(t *testing.T) {
|
|||||||
var event map[string]any
|
var event map[string]any
|
||||||
require.NoError(t, json.Unmarshal([]byte(eventJSON), &event))
|
require.NoError(t, json.Unmarshal([]byte(eventJSON), &event))
|
||||||
|
|
||||||
if u, ok := event["usage"].(map[string]any); ok {
|
usage, ok := event["usage"].(map[string]any)
|
||||||
reconcileCachedTokens(u)
|
require.True(t, ok)
|
||||||
}
|
reconcileCachedTokens(usage)
|
||||||
|
|
||||||
usage := event["usage"].(map[string]any)
|
|
||||||
_, hasCacheRead := usage["cache_read_input_tokens"]
|
_, hasCacheRead := usage["cache_read_input_tokens"]
|
||||||
assert.False(t, hasCacheRead, "不应为原生 Claude 响应注入 cache_read_input_tokens")
|
assert.False(t, hasCacheRead, "不应为原生 Claude 响应注入 cache_read_input_tokens")
|
||||||
}
|
}
|
||||||
@@ -251,20 +251,8 @@ func TestNonStreamingReconcile_NativeClaude(t *testing.T) {
|
|||||||
}
|
}
|
||||||
require.NoError(t, json.Unmarshal(body, &response))
|
require.NoError(t, json.Unmarshal(body, &response))
|
||||||
|
|
||||||
originalBody := make([]byte, len(body))
|
// CacheReadInputTokens == 30,条件不成立,整个 reconcile 分支不会执行
|
||||||
copy(originalBody, body)
|
assert.NotZero(t, response.Usage.CacheReadInputTokens)
|
||||||
|
|
||||||
if response.Usage.CacheReadInputTokens == 0 {
|
|
||||||
cachedTokens := gjson.GetBytes(body, "usage.cached_tokens").Int()
|
|
||||||
if cachedTokens > 0 {
|
|
||||||
response.Usage.CacheReadInputTokens = int(cachedTokens)
|
|
||||||
if newBody, err := sjson.SetBytes(body, "usage.cache_read_input_tokens", cachedTokens); err == nil {
|
|
||||||
body = newBody
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 不应修改
|
|
||||||
assert.Equal(t, 30, response.Usage.CacheReadInputTokens)
|
assert.Equal(t, 30, response.Usage.CacheReadInputTokens)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -579,6 +579,7 @@ func (s *PricingService) extractBaseName(model string) string {
|
|||||||
func (s *PricingService) matchByModelFamily(model string) *LiteLLMModelPricing {
|
func (s *PricingService) matchByModelFamily(model string) *LiteLLMModelPricing {
|
||||||
// Claude模型系列匹配规则
|
// Claude模型系列匹配规则
|
||||||
familyPatterns := map[string][]string{
|
familyPatterns := map[string][]string{
|
||||||
|
"opus-4.6": {"claude-opus-4.6", "claude-opus-4-6"},
|
||||||
"opus-4.5": {"claude-opus-4.5", "claude-opus-4-5"},
|
"opus-4.5": {"claude-opus-4.5", "claude-opus-4-5"},
|
||||||
"opus-4": {"claude-opus-4", "claude-3-opus"},
|
"opus-4": {"claude-opus-4", "claude-3-opus"},
|
||||||
"sonnet-4.5": {"claude-sonnet-4.5", "claude-sonnet-4-5"},
|
"sonnet-4.5": {"claude-sonnet-4.5", "claude-sonnet-4-5"},
|
||||||
|
|||||||
@@ -707,6 +707,7 @@ const groupIds = ref<number[]>([])
|
|||||||
|
|
||||||
// All models list (combined Anthropic + OpenAI)
|
// All models list (combined Anthropic + OpenAI)
|
||||||
const allModels = [
|
const allModels = [
|
||||||
|
{ value: 'claude-opus-4-6', label: 'Claude Opus 4.6' },
|
||||||
{ value: 'claude-opus-4-5-20251101', label: 'Claude Opus 4.5' },
|
{ value: 'claude-opus-4-5-20251101', label: 'Claude Opus 4.5' },
|
||||||
{ value: 'claude-sonnet-4-20250514', label: 'Claude Sonnet 4' },
|
{ value: 'claude-sonnet-4-20250514', label: 'Claude Sonnet 4' },
|
||||||
{ value: 'claude-sonnet-4-5-20250929', label: 'Claude Sonnet 4.5' },
|
{ value: 'claude-sonnet-4-5-20250929', label: 'Claude Sonnet 4.5' },
|
||||||
@@ -746,6 +747,13 @@ const presetMappings = [
|
|||||||
color:
|
color:
|
||||||
'bg-purple-100 text-purple-700 hover:bg-purple-200 dark:bg-purple-900/30 dark:text-purple-400'
|
'bg-purple-100 text-purple-700 hover:bg-purple-200 dark:bg-purple-900/30 dark:text-purple-400'
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: 'Opus 4.6',
|
||||||
|
from: 'claude-opus-4-6',
|
||||||
|
to: 'claude-opus-4-6',
|
||||||
|
color:
|
||||||
|
'bg-purple-100 text-purple-700 hover:bg-purple-200 dark:bg-purple-900/30 dark:text-purple-400'
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: 'Opus->Sonnet',
|
label: 'Opus->Sonnet',
|
||||||
from: 'claude-opus-4-5-20251101',
|
from: 'claude-opus-4-5-20251101',
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ export const claudeModels = [
|
|||||||
'claude-opus-4-1-20250805',
|
'claude-opus-4-1-20250805',
|
||||||
'claude-sonnet-4-5-20250929', 'claude-haiku-4-5-20251001',
|
'claude-sonnet-4-5-20250929', 'claude-haiku-4-5-20251001',
|
||||||
'claude-opus-4-5-20251101',
|
'claude-opus-4-5-20251101',
|
||||||
|
'claude-opus-4-6',
|
||||||
'claude-2.1', 'claude-2.0', 'claude-instant-1.2'
|
'claude-2.1', 'claude-2.0', 'claude-instant-1.2'
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -227,9 +228,10 @@ const anthropicPresetMappings = [
|
|||||||
{ label: 'Sonnet 4', from: 'claude-sonnet-4-20250514', to: 'claude-sonnet-4-20250514', color: 'bg-blue-100 text-blue-700 hover:bg-blue-200 dark:bg-blue-900/30 dark:text-blue-400' },
|
{ label: 'Sonnet 4', from: 'claude-sonnet-4-20250514', to: 'claude-sonnet-4-20250514', color: 'bg-blue-100 text-blue-700 hover:bg-blue-200 dark:bg-blue-900/30 dark:text-blue-400' },
|
||||||
{ label: 'Sonnet 4.5', from: 'claude-sonnet-4-5-20250929', to: 'claude-sonnet-4-5-20250929', color: 'bg-indigo-100 text-indigo-700 hover:bg-indigo-200 dark:bg-indigo-900/30 dark:text-indigo-400' },
|
{ label: 'Sonnet 4.5', from: 'claude-sonnet-4-5-20250929', to: 'claude-sonnet-4-5-20250929', color: 'bg-indigo-100 text-indigo-700 hover:bg-indigo-200 dark:bg-indigo-900/30 dark:text-indigo-400' },
|
||||||
{ label: 'Opus 4.5', from: 'claude-opus-4-5-20251101', to: 'claude-opus-4-5-20251101', color: 'bg-purple-100 text-purple-700 hover:bg-purple-200 dark:bg-purple-900/30 dark:text-purple-400' },
|
{ label: 'Opus 4.5', from: 'claude-opus-4-5-20251101', to: 'claude-opus-4-5-20251101', color: 'bg-purple-100 text-purple-700 hover:bg-purple-200 dark:bg-purple-900/30 dark:text-purple-400' },
|
||||||
|
{ label: 'Opus 4.6', from: 'claude-opus-4-6', to: 'claude-opus-4-6', color: 'bg-purple-100 text-purple-700 hover:bg-purple-200 dark:bg-purple-900/30 dark:text-purple-400' },
|
||||||
{ label: 'Haiku 3.5', from: 'claude-3-5-haiku-20241022', to: 'claude-3-5-haiku-20241022', color: 'bg-green-100 text-green-700 hover:bg-green-200 dark:bg-green-900/30 dark:text-green-400' },
|
{ label: 'Haiku 3.5', from: 'claude-3-5-haiku-20241022', to: 'claude-3-5-haiku-20241022', color: 'bg-green-100 text-green-700 hover:bg-green-200 dark:bg-green-900/30 dark:text-green-400' },
|
||||||
{ label: 'Haiku 4.5', from: 'claude-haiku-4-5-20251001', to: 'claude-haiku-4-5-20251001', color: 'bg-emerald-100 text-emerald-700 hover:bg-emerald-200 dark:bg-emerald-900/30 dark:text-emerald-400' },
|
{ label: 'Haiku 4.5', from: 'claude-haiku-4-5-20251001', to: 'claude-haiku-4-5-20251001', color: 'bg-emerald-100 text-emerald-700 hover:bg-emerald-200 dark:bg-emerald-900/30 dark:text-emerald-400' },
|
||||||
{ label: 'Opus->Sonnet', from: 'claude-opus-4-5-20251101', to: 'claude-sonnet-4-5-20250929', color: 'bg-amber-100 text-amber-700 hover:bg-amber-200 dark:bg-amber-900/30 dark:text-amber-400' }
|
{ label: 'Opus->Sonnet', from: 'claude-opus-4-6', to: 'claude-sonnet-4-5-20250929', color: 'bg-amber-100 text-amber-700 hover:bg-amber-200 dark:bg-amber-900/30 dark:text-amber-400' }
|
||||||
]
|
]
|
||||||
|
|
||||||
const openaiPresetMappings = [
|
const openaiPresetMappings = [
|
||||||
|
|||||||
Reference in New Issue
Block a user