mirror of
https://github.com/CJackHwang/ds2api.git
synced 2026-05-23 10:57:44 +08:00
feat: revamp DeepSeek v4 model handling
- replace legacy DeepSeek ids with the new deepseek-v4 model family\n- move thinking control to request parameters and preserve assistant reasoning content\n- switch history split to IGNORE transcript injection and map upload auth failures to 401\n- update admin defaults, API docs, samples, and tests for the new model scheme
This commit is contained in:
@@ -10,9 +10,9 @@ func TestStandardRequestCompletionPayloadSetsModelTypeFromResolvedModel(t *testi
|
||||
search bool
|
||||
modelType string
|
||||
}{
|
||||
{name: "default", model: "deepseek-chat", thinking: false, search: false, modelType: "default"},
|
||||
{name: "expert", model: "deepseek-expert-reasoner", thinking: true, search: false, modelType: "expert"},
|
||||
{name: "vision", model: "deepseek-vision-chat-search", thinking: false, search: true, modelType: "vision"},
|
||||
{name: "default", model: "deepseek-v4-flash", thinking: false, search: false, modelType: "default"},
|
||||
{name: "expert", model: "deepseek-v4-pro", thinking: true, search: false, modelType: "expert"},
|
||||
{name: "vision", model: "deepseek-v4-vision-search", thinking: false, search: true, modelType: "vision"},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
|
||||
53
internal/util/thinking.go
Normal file
53
internal/util/thinking.go
Normal file
@@ -0,0 +1,53 @@
|
||||
package util
|
||||
|
||||
import "strings"
|
||||
|
||||
func ResolveThinkingEnabled(req map[string]any, defaultEnabled bool) bool {
|
||||
if enabled, ok := parseThinkingSetting(req["thinking"]); ok {
|
||||
return enabled
|
||||
}
|
||||
if extraBody, ok := req["extra_body"].(map[string]any); ok {
|
||||
if enabled, ok := parseThinkingSetting(extraBody["thinking"]); ok {
|
||||
return enabled
|
||||
}
|
||||
}
|
||||
if enabled, ok := parseReasoningEffort(req["reasoning_effort"]); ok {
|
||||
return enabled
|
||||
}
|
||||
return defaultEnabled
|
||||
}
|
||||
|
||||
func parseThinkingSetting(raw any) (bool, bool) {
|
||||
switch v := raw.(type) {
|
||||
case string:
|
||||
switch strings.ToLower(strings.TrimSpace(v)) {
|
||||
case "enabled":
|
||||
return true, true
|
||||
case "disabled":
|
||||
return false, true
|
||||
default:
|
||||
return false, false
|
||||
}
|
||||
case map[string]any:
|
||||
if typ, ok := v["type"]; ok {
|
||||
return parseThinkingSetting(typ)
|
||||
}
|
||||
}
|
||||
return false, false
|
||||
}
|
||||
|
||||
func parseReasoningEffort(raw any) (bool, bool) {
|
||||
switch strings.ToLower(strings.TrimSpace(toString(raw))) {
|
||||
case "low", "medium", "high", "xhigh":
|
||||
return true, true
|
||||
default:
|
||||
return false, false
|
||||
}
|
||||
}
|
||||
|
||||
func toString(raw any) string {
|
||||
if s, ok := raw.(string); ok {
|
||||
return s
|
||||
}
|
||||
return ""
|
||||
}
|
||||
44
internal/util/thinking_test.go
Normal file
44
internal/util/thinking_test.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package util
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestResolveThinkingEnabledPriority(t *testing.T) {
|
||||
req := map[string]any{
|
||||
"thinking": map[string]any{"type": "disabled"},
|
||||
"extra_body": map[string]any{
|
||||
"thinking": map[string]any{"type": "enabled"},
|
||||
},
|
||||
"reasoning_effort": "high",
|
||||
}
|
||||
if got := ResolveThinkingEnabled(req, true); got {
|
||||
t.Fatalf("expected top-level thinking to win, got enabled=%v", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolveThinkingEnabledUsesExtraBodyFallback(t *testing.T) {
|
||||
req := map[string]any{
|
||||
"extra_body": map[string]any{
|
||||
"thinking": map[string]any{"type": "disabled"},
|
||||
},
|
||||
}
|
||||
if got := ResolveThinkingEnabled(req, true); got {
|
||||
t.Fatalf("expected extra_body thinking to disable, got enabled=%v", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolveThinkingEnabledMapsReasoningEffortToEnabled(t *testing.T) {
|
||||
for _, effort := range []string{"low", "medium", "high", "xhigh"} {
|
||||
if got := ResolveThinkingEnabled(map[string]any{"reasoning_effort": effort}, false); !got {
|
||||
t.Fatalf("expected reasoning_effort=%s to enable thinking", effort)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolveThinkingEnabledDefaultsWhenUnset(t *testing.T) {
|
||||
if !ResolveThinkingEnabled(nil, true) {
|
||||
t.Fatal("expected default thinking=true when unset")
|
||||
}
|
||||
if ResolveThinkingEnabled(nil, false) {
|
||||
t.Fatal("expected default thinking=false when unset")
|
||||
}
|
||||
}
|
||||
@@ -349,14 +349,14 @@ func TestConvertClaudeToDeepSeekNoSystem(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestConvertClaudeToDeepSeekOpusUsesSlowMapping(t *testing.T) {
|
||||
t.Setenv("DS2API_CONFIG_JSON", `{"keys":[],"accounts":[],"claude_mapping":{"fast":"deepseek-chat","slow":"deepseek-reasoner"}}`)
|
||||
t.Setenv("DS2API_CONFIG_JSON", `{"keys":[],"accounts":[],"claude_mapping":{"fast":"deepseek-v4-flash","slow":"deepseek-v4-pro"}}`)
|
||||
store := config.LoadStore()
|
||||
req := map[string]any{
|
||||
"model": "claude-opus-4-6",
|
||||
"messages": []any{map[string]any{"role": "user", "content": "Hi"}},
|
||||
}
|
||||
out := ConvertClaudeToDeepSeek(req, store)
|
||||
if out["model"] != "deepseek-reasoner" {
|
||||
if out["model"] != "deepseek-v4-pro" {
|
||||
t.Fatalf("expected opus to use slow mapping, got %q", out["model"])
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user