mirror of
https://github.com/router-for-me/CLIProxyAPI.git
synced 2026-10-19 14:09:05 +08:00
fix(claude): refine model version parsing for assistant prefill rejection
- Strip provider namespaces and prefix before evaluating model family - Parse major and minor version numbers dynamically while ignoring snapshot dates - Correctly identify unsupported assistant prefill models for Fable, Opus 5+, and Sonnet 4.6+ Closes: #5483
This commit is contained in:
@@ -727,12 +727,39 @@ func stripTrailingClaudeThinkingBlocks(messages [][]byte) [][]byte {
|
||||
// disallows trailing assistant prefill in its conversation history.
|
||||
func claudeModelRejectsAssistantPrefill(modelName string) bool {
|
||||
normalized := strings.ToLower(strings.TrimSpace(modelName))
|
||||
for _, family := range []string{"fable", "opus-5", "sonnet-4-6"} {
|
||||
if strings.Contains(normalized, family) {
|
||||
return true
|
||||
}
|
||||
// Provider namespaces are not part of the model family.
|
||||
if index := strings.LastIndexByte(normalized, '/'); index >= 0 {
|
||||
normalized = normalized[index+1:]
|
||||
}
|
||||
return false
|
||||
normalized = strings.TrimPrefix(normalized, "claude-")
|
||||
tokens := strings.Split(strings.ReplaceAll(normalized, ".", "-"), "-")
|
||||
if tokens[0] == "fable" {
|
||||
return true
|
||||
}
|
||||
if len(tokens) < 2 || (tokens[0] != "opus" && tokens[0] != "sonnet") {
|
||||
return false
|
||||
}
|
||||
parseVersion := func(token string) int {
|
||||
// Eight-digit snapshot dates must never be treated as versions.
|
||||
if token == "" || len(token) >= 8 {
|
||||
return -1
|
||||
}
|
||||
for _, digit := range token {
|
||||
if digit < '0' || digit > '9' {
|
||||
return -1
|
||||
}
|
||||
}
|
||||
version, errAtoi := strconv.Atoi(token)
|
||||
if errAtoi != nil {
|
||||
return -1
|
||||
}
|
||||
return version
|
||||
}
|
||||
major := parseVersion(tokens[1])
|
||||
if major >= 5 {
|
||||
return true
|
||||
}
|
||||
return tokens[0] == "sonnet" && major == 4 && len(tokens) > 2 && parseVersion(tokens[2]) >= 6
|
||||
}
|
||||
|
||||
// responsesSystemUnsupportedBlock represents a system-level content part that
|
||||
|
||||
@@ -2036,6 +2036,18 @@ func TestConvertOpenAIResponsesRequestToClaude_UnsupportedPrefillModelsStripTrai
|
||||
"claude-fable-5",
|
||||
"claude-opus-5",
|
||||
"claude-sonnet-4-6",
|
||||
"fable",
|
||||
"opus-5",
|
||||
"sonnet-4.6",
|
||||
"anthropic/claude-opus-5-thinking",
|
||||
"claude-sonnet-4.6",
|
||||
"claude-sonnet-4-7",
|
||||
"claude-sonnet-4-10",
|
||||
"claude-sonnet-5",
|
||||
"claude-opus-6",
|
||||
"claude-opus-5.1",
|
||||
"claude-sonnet-4-6-20260217",
|
||||
" ANTHROPIC/CLAUDE-OPUS-5-THINKING ",
|
||||
}
|
||||
for _, model := range unsupportedModels {
|
||||
t.Run(model, func(t *testing.T) {
|
||||
@@ -2065,6 +2077,20 @@ func TestConvertOpenAIResponsesRequestToClaude_SupportedPrefillModelsPreserveAss
|
||||
supportedModels := []string{
|
||||
"claude-sonnet-4-5",
|
||||
"claude-haiku-4-5",
|
||||
"claude-3-opus-20240229",
|
||||
"claude-opus-20240229",
|
||||
"claude-sonnet-4-20260217",
|
||||
"claude-sonnet-4.5",
|
||||
"not-a-fable-model",
|
||||
"my-custom-opus-5-wrapper",
|
||||
"my-sonnet-4-6-wrapper",
|
||||
"claude-fabled-5",
|
||||
"claude-opus-5foo",
|
||||
"claude-sonnet-4-6foo",
|
||||
"fable/gpt-4o",
|
||||
"opus",
|
||||
"sonnet",
|
||||
"",
|
||||
}
|
||||
for _, model := range supportedModels {
|
||||
t.Run(model, func(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user