Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
phsl
/
new-api
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Unverified
Commit
47d7bca2
authored
Apr 17, 2026
by
papersnake
Committed by
GitHub
Apr 17, 2026
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: support claude-opus-4-7 (#4293)
* feat: support claude-opus-4-7 * feat: summarized display for opus 4.7
parent
22e509c1
Show whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
81 additions
and
4 deletions
+81
-4
dto/claude.go
+5
-0
relay/channel/aws/constants.go
+6
-0
relay/channel/claude/constants.go
+7
-0
relay/channel/claude/relay-claude.go
+21
-2
relay/channel/vertex/adaptor.go
+1
-0
relay/claude_handler.go
+20
-1
setting/ratio_setting/cache_ratio.go
+14
-0
setting/ratio_setting/model_ratio.go
+6
-0
setting/reasoning/suffix.go
+1
-1
No files found.
dto/claude.go
View file @
47d7bca2
...
...
@@ -448,6 +448,11 @@ func ProcessTools(tools []any) ([]*Tool, []*ClaudeWebSearchTool) {
type
Thinking
struct
{
Type
string
`json:"type,omitempty"`
BudgetTokens
*
int
`json:"budget_tokens,omitempty"`
// Display controls whether thinking content is returned in the response.
// Used with adaptive thinking on Claude Opus 4.7+: "summarized" restores
// the visible summary that was default on Opus 4.6; "omitted" (default on
// 4.7) suppresses it. Pass-through field from upstream Anthropic API.
Display
string
`json:"display,omitempty"`
}
func
(
c
*
Thinking
)
GetBudgetTokens
()
int
{
...
...
relay/channel/aws/constants.go
View file @
47d7bca2
...
...
@@ -18,6 +18,7 @@ var awsModelIDMap = map[string]string{
"claude-haiku-4-5-20251001"
:
"anthropic.claude-haiku-4-5-20251001-v1:0"
,
"claude-opus-4-5-20251101"
:
"anthropic.claude-opus-4-5-20251101-v1:0"
,
"claude-opus-4-6"
:
"anthropic.claude-opus-4-6-v1"
,
"claude-opus-4-7"
:
"anthropic.claude-opus-4-7"
,
// Nova models
"nova-micro-v1:0"
:
"amazon.nova-micro-v1:0"
,
"nova-lite-v1:0"
:
"amazon.nova-lite-v1:0"
,
...
...
@@ -91,6 +92,11 @@ var awsModelCanCrossRegionMap = map[string]map[string]bool{
"ap"
:
true
,
"eu"
:
true
,
},
"anthropic.claude-opus-4-7"
:
{
"us"
:
true
,
"ap"
:
true
,
"eu"
:
true
,
},
"anthropic.claude-haiku-4-5-20251001-v1:0"
:
{
"us"
:
true
,
"ap"
:
true
,
...
...
relay/channel/claude/constants.go
View file @
47d7bca2
...
...
@@ -26,6 +26,13 @@ var ModelList = []string{
"claude-opus-4-6-medium"
,
"claude-opus-4-6-low"
,
"claude-sonnet-4-6"
,
"claude-opus-4-7"
,
"claude-opus-4-7-max"
,
"claude-opus-4-7-xhigh"
,
"claude-opus-4-7-high"
,
"claude-opus-4-7-medium"
,
"claude-opus-4-7-low"
,
"claude-opus-4-7-thinking"
,
}
var
ChannelName
=
"claude"
relay/channel/claude/relay-claude.go
View file @
47d7bca2
...
...
@@ -154,17 +154,35 @@ func RequestOpenAI2ClaudeMessage(c *gin.Context, textRequest dto.GeneralOpenAIRe
}
if
baseModel
,
effortLevel
,
ok
:=
reasoning
.
TrimEffortSuffix
(
textRequest
.
Model
);
ok
&&
effortLevel
!=
""
&&
strings
.
HasPrefix
(
textRequest
.
Model
,
"claude-opus-4-6"
)
{
(
strings
.
HasPrefix
(
textRequest
.
Model
,
"claude-opus-4-6"
)
||
strings
.
HasPrefix
(
textRequest
.
Model
,
"claude-opus-4-7"
)
)
{
claudeRequest
.
Model
=
baseModel
claudeRequest
.
Thinking
=
&
dto
.
Thinking
{
Type
:
"adaptive"
,
}
claudeRequest
.
OutputConfig
=
json
.
RawMessage
(
fmt
.
Sprintf
(
`{"effort":"%s"}`
,
effortLevel
))
if
strings
.
HasPrefix
(
baseModel
,
"claude-opus-4-7"
)
{
// Opus 4.7 rejects non-default temperature/top_p/top_k with 400
// and defaults display to "omitted"; restore the 4.6 visible summary.
claudeRequest
.
Thinking
.
Display
=
"summarized"
claudeRequest
.
Temperature
=
nil
claudeRequest
.
TopP
=
nil
claudeRequest
.
TopK
=
nil
}
else
{
claudeRequest
.
TopP
=
nil
claudeRequest
.
Temperature
=
common
.
GetPointer
[
float64
](
1.0
)
}
}
else
if
model_setting
.
GetClaudeSettings
()
.
ThinkingAdapterEnabled
&&
strings
.
HasSuffix
(
textRequest
.
Model
,
"-thinking"
)
{
trimmedModel
:=
strings
.
TrimSuffix
(
textRequest
.
Model
,
"-thinking"
)
if
strings
.
HasPrefix
(
trimmedModel
,
"claude-opus-4-7"
)
{
// Opus 4.7 rejects thinking.type="enabled"; use adaptive at high effort.
claudeRequest
.
Thinking
=
&
dto
.
Thinking
{
Type
:
"adaptive"
,
Display
:
"summarized"
}
claudeRequest
.
OutputConfig
=
json
.
RawMessage
(
`{"effort":"high"}`
)
claudeRequest
.
Temperature
=
nil
claudeRequest
.
TopP
=
nil
claudeRequest
.
TopK
=
nil
}
else
{
// 因为BudgetTokens 必须大于1024
if
claudeRequest
.
MaxTokens
==
nil
||
*
claudeRequest
.
MaxTokens
<
1280
{
claudeRequest
.
MaxTokens
=
common
.
GetPointer
[
uint
](
1280
)
...
...
@@ -179,8 +197,9 @@ func RequestOpenAI2ClaudeMessage(c *gin.Context, textRequest dto.GeneralOpenAIRe
// https://docs.anthropic.com/en/docs/build-with-claude/extended-thinking#important-considerations-when-using-extended-thinking
claudeRequest
.
TopP
=
nil
claudeRequest
.
Temperature
=
common
.
GetPointer
[
float64
](
1.0
)
}
if
!
model_setting
.
ShouldPreserveThinkingSuffix
(
textRequest
.
Model
)
{
claudeRequest
.
Model
=
strings
.
TrimSuffix
(
textRequest
.
Model
,
"-thinking"
)
claudeRequest
.
Model
=
trimmedModel
}
}
...
...
relay/channel/vertex/adaptor.go
View file @
47d7bca2
...
...
@@ -44,6 +44,7 @@ var claudeModelMap = map[string]string{
"claude-haiku-4-5-20251001"
:
"claude-haiku-4-5@20251001"
,
"claude-opus-4-5-20251101"
:
"claude-opus-4-5@20251101"
,
"claude-opus-4-6"
:
"claude-opus-4-6"
,
"claude-opus-4-7"
:
"claude-opus-4-7"
,
}
const
anthropicVersion
=
"vertex-2023-10-16"
...
...
relay/claude_handler.go
View file @
47d7bca2
...
...
@@ -53,17 +53,35 @@ func ClaudeHelper(c *gin.Context, info *relaycommon.RelayInfo) (newAPIError *typ
}
if
baseModel
,
effortLevel
,
ok
:=
reasoning
.
TrimEffortSuffix
(
request
.
Model
);
ok
&&
effortLevel
!=
""
&&
strings
.
HasPrefix
(
request
.
Model
,
"claude-opus-4-6"
)
{
(
strings
.
HasPrefix
(
request
.
Model
,
"claude-opus-4-6"
)
||
strings
.
HasPrefix
(
request
.
Model
,
"claude-opus-4-7"
)
)
{
request
.
Model
=
baseModel
request
.
Thinking
=
&
dto
.
Thinking
{
Type
:
"adaptive"
,
}
request
.
OutputConfig
=
json
.
RawMessage
(
fmt
.
Sprintf
(
`{"effort":"%s"}`
,
effortLevel
))
if
strings
.
HasPrefix
(
request
.
Model
,
"claude-opus-4-7"
)
{
// Opus 4.7 rejects non-default temperature/top_p/top_k with 400
// and defaults display to "omitted"; restore the 4.6 visible summary.
request
.
Thinking
.
Display
=
"summarized"
request
.
Temperature
=
nil
request
.
TopP
=
nil
request
.
TopK
=
nil
}
else
{
request
.
Temperature
=
common
.
GetPointer
[
float64
](
1.0
)
}
info
.
UpstreamModelName
=
request
.
Model
}
else
if
model_setting
.
GetClaudeSettings
()
.
ThinkingAdapterEnabled
&&
strings
.
HasSuffix
(
request
.
Model
,
"-thinking"
)
{
if
request
.
Thinking
==
nil
{
baseModel
:=
strings
.
TrimSuffix
(
request
.
Model
,
"-thinking"
)
if
strings
.
HasPrefix
(
baseModel
,
"claude-opus-4-7"
)
{
// Opus 4.7 rejects thinking.type="enabled"; use adaptive at high effort.
request
.
Thinking
=
&
dto
.
Thinking
{
Type
:
"adaptive"
,
Display
:
"summarized"
}
request
.
OutputConfig
=
json
.
RawMessage
(
`{"effort":"high"}`
)
request
.
Temperature
=
nil
request
.
TopP
=
nil
request
.
TopK
=
nil
}
else
{
// 因为BudgetTokens 必须大于1024
if
request
.
MaxTokens
==
nil
||
*
request
.
MaxTokens
<
1280
{
request
.
MaxTokens
=
common
.
GetPointer
[
uint
](
1280
)
...
...
@@ -78,6 +96,7 @@ func ClaudeHelper(c *gin.Context, info *relaycommon.RelayInfo) (newAPIError *typ
// https://docs.anthropic.com/en/docs/build-with-claude/extended-thinking#important-considerations-when-using-extended-thinking
request
.
Temperature
=
common
.
GetPointer
[
float64
](
1.0
)
}
}
if
!
model_setting
.
ShouldPreserveThinkingSuffix
(
info
.
OriginModelName
)
{
request
.
Model
=
strings
.
TrimSuffix
(
request
.
Model
,
"-thinking"
)
}
...
...
setting/ratio_setting/cache_ratio.go
View file @
47d7bca2
...
...
@@ -64,6 +64,13 @@ var defaultCacheRatio = map[string]float64{
"claude-opus-4-6-high"
:
0.1
,
"claude-opus-4-6-medium"
:
0.1
,
"claude-opus-4-6-low"
:
0.1
,
"claude-opus-4-7"
:
0.1
,
"claude-opus-4-7-thinking"
:
0.1
,
"claude-opus-4-7-max"
:
0.1
,
"claude-opus-4-7-xhigh"
:
0.1
,
"claude-opus-4-7-high"
:
0.1
,
"claude-opus-4-7-medium"
:
0.1
,
"claude-opus-4-7-low"
:
0.1
,
}
var
defaultCreateCacheRatio
=
map
[
string
]
float64
{
...
...
@@ -92,6 +99,13 @@ var defaultCreateCacheRatio = map[string]float64{
"claude-opus-4-6-high"
:
1.25
,
"claude-opus-4-6-medium"
:
1.25
,
"claude-opus-4-6-low"
:
1.25
,
"claude-opus-4-7"
:
1.25
,
"claude-opus-4-7-thinking"
:
1.25
,
"claude-opus-4-7-max"
:
1.25
,
"claude-opus-4-7-xhigh"
:
1.25
,
"claude-opus-4-7-high"
:
1.25
,
"claude-opus-4-7-medium"
:
1.25
,
"claude-opus-4-7-low"
:
1.25
,
}
//var defaultCreateCacheRatio = map[string]float64{}
...
...
setting/ratio_setting/model_ratio.go
View file @
47d7bca2
...
...
@@ -146,6 +146,12 @@ var defaultModelRatio = map[string]float64{
"claude-opus-4-6-high"
:
2.5
,
"claude-opus-4-6-medium"
:
2.5
,
"claude-opus-4-6-low"
:
2.5
,
"claude-opus-4-7"
:
2.5
,
"claude-opus-4-7-max"
:
2.5
,
"claude-opus-4-7-xhigh"
:
2.5
,
"claude-opus-4-7-high"
:
2.5
,
"claude-opus-4-7-medium"
:
2.5
,
"claude-opus-4-7-low"
:
2.5
,
"claude-3-opus-20240229"
:
7.5
,
// $15 / 1M tokens
"claude-opus-4-20250514"
:
7.5
,
"claude-opus-4-1-20250805"
:
7.5
,
...
...
setting/reasoning/suffix.go
View file @
47d7bca2
...
...
@@ -6,7 +6,7 @@ import (
"github.com/samber/lo"
)
var
EffortSuffixes
=
[]
string
{
"-max"
,
"-high"
,
"-medium"
,
"-low"
,
"-minimal"
}
var
EffortSuffixes
=
[]
string
{
"-max"
,
"-
xhigh"
,
"-
high"
,
"-medium"
,
"-low"
,
"-minimal"
}
// TrimEffortSuffix -> modelName level(low) exists
func
TrimEffortSuffix
(
modelName
string
)
(
string
,
string
,
bool
)
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment