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
Commit
6c28de89
authored
Feb 08, 2026
by
Calcium-Ion
Committed by
GitHub
Feb 08, 2026
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #2889 from seefs001/feature/messages2responses
feat: /v1/messages -> /v1/responses
parents
c494c262
3d0c75f4
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
79 additions
and
19 deletions
+79
-19
relay/channel/openai/adaptor.go
+3
-1
relay/channel/openai/chat_via_responses.go
+59
-18
relay/claude_handler.go
+17
-0
No files found.
relay/channel/openai/adaptor.go
View file @
6c28de89
...
@@ -171,7 +171,9 @@ func (a *Adaptor) GetRequestURL(info *relaycommon.RelayInfo) (string, error) {
...
@@ -171,7 +171,9 @@ func (a *Adaptor) GetRequestURL(info *relaycommon.RelayInfo) (string, error) {
url
=
strings
.
Replace
(
url
,
"{model}"
,
info
.
UpstreamModelName
,
-
1
)
url
=
strings
.
Replace
(
url
,
"{model}"
,
info
.
UpstreamModelName
,
-
1
)
return
url
,
nil
return
url
,
nil
default
:
default
:
if
info
.
RelayFormat
==
types
.
RelayFormatClaude
||
info
.
RelayFormat
==
types
.
RelayFormatGemini
{
if
(
info
.
RelayFormat
==
types
.
RelayFormatClaude
||
info
.
RelayFormat
==
types
.
RelayFormatGemini
)
&&
info
.
RelayMode
!=
relayconstant
.
RelayModeResponses
&&
info
.
RelayMode
!=
relayconstant
.
RelayModeResponsesCompact
{
return
fmt
.
Sprintf
(
"%s/v1/chat/completions"
,
info
.
ChannelBaseUrl
),
nil
return
fmt
.
Sprintf
(
"%s/v1/chat/completions"
,
info
.
ChannelBaseUrl
),
nil
}
}
return
relaycommon
.
GetFullRequestURL
(
info
.
ChannelBaseUrl
,
info
.
RequestURLPath
,
info
.
ChannelType
),
nil
return
relaycommon
.
GetFullRequestURL
(
info
.
ChannelBaseUrl
,
info
.
RequestURLPath
,
info
.
ChannelType
),
nil
...
...
relay/channel/openai/chat_via_responses.go
View file @
6c28de89
...
@@ -71,12 +71,22 @@ func OaiResponsesToChatHandler(c *gin.Context, info *relaycommon.RelayInfo, resp
...
@@ -71,12 +71,22 @@ func OaiResponsesToChatHandler(c *gin.Context, info *relaycommon.RelayInfo, resp
chatResp
.
Usage
=
*
usage
chatResp
.
Usage
=
*
usage
}
}
chatBody
,
err
:=
common
.
Marshal
(
chatResp
)
var
responseBody
[]
byte
switch
info
.
RelayFormat
{
case
types
.
RelayFormatClaude
:
claudeResp
:=
service
.
ResponseOpenAI2Claude
(
chatResp
,
info
)
responseBody
,
err
=
common
.
Marshal
(
claudeResp
)
case
types
.
RelayFormatGemini
:
geminiResp
:=
service
.
ResponseOpenAI2Gemini
(
chatResp
,
info
)
responseBody
,
err
=
common
.
Marshal
(
geminiResp
)
default
:
responseBody
,
err
=
common
.
Marshal
(
chatResp
)
}
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
types
.
NewOpenAIError
(
err
,
types
.
ErrorCodeJsonMarshalFailed
,
http
.
StatusInternalServerError
)
return
nil
,
types
.
NewOpenAIError
(
err
,
types
.
ErrorCodeJsonMarshalFailed
,
http
.
StatusInternalServerError
)
}
}
service
.
IOCopyBytesGracefully
(
c
,
resp
,
chat
Body
)
service
.
IOCopyBytesGracefully
(
c
,
resp
,
response
Body
)
return
usage
,
nil
return
usage
,
nil
}
}
...
@@ -110,12 +120,39 @@ func OaiResponsesToChatStreamHandler(c *gin.Context, info *relaycommon.RelayInfo
...
@@ -110,12 +120,39 @@ func OaiResponsesToChatStreamHandler(c *gin.Context, info *relaycommon.RelayInfo
needsReasoningSummarySeparator
:=
false
needsReasoningSummarySeparator
:=
false
//reasoningSummaryTextByKey := make(map[string]string)
//reasoningSummaryTextByKey := make(map[string]string)
if
info
.
RelayFormat
==
types
.
RelayFormatClaude
&&
info
.
ClaudeConvertInfo
==
nil
{
info
.
ClaudeConvertInfo
=
&
relaycommon
.
ClaudeConvertInfo
{
LastMessagesType
:
relaycommon
.
LastMessageTypeNone
}
}
sendChatChunk
:=
func
(
chunk
*
dto
.
ChatCompletionsStreamResponse
)
bool
{
if
chunk
==
nil
{
return
true
}
if
info
.
RelayFormat
==
types
.
RelayFormatOpenAI
{
if
err
:=
helper
.
ObjectData
(
c
,
chunk
);
err
!=
nil
{
streamErr
=
types
.
NewOpenAIError
(
err
,
types
.
ErrorCodeBadResponse
,
http
.
StatusInternalServerError
)
return
false
}
return
true
}
chunkData
,
err
:=
common
.
Marshal
(
chunk
)
if
err
!=
nil
{
streamErr
=
types
.
NewOpenAIError
(
err
,
types
.
ErrorCodeJsonMarshalFailed
,
http
.
StatusInternalServerError
)
return
false
}
if
err
:=
HandleStreamFormat
(
c
,
info
,
string
(
chunkData
),
false
,
false
);
err
!=
nil
{
streamErr
=
types
.
NewOpenAIError
(
err
,
types
.
ErrorCodeBadResponse
,
http
.
StatusInternalServerError
)
return
false
}
return
true
}
sendStartIfNeeded
:=
func
()
bool
{
sendStartIfNeeded
:=
func
()
bool
{
if
sentStart
{
if
sentStart
{
return
true
return
true
}
}
if
err
:=
helper
.
ObjectData
(
c
,
helper
.
GenerateStartEmptyResponse
(
responseId
,
createAt
,
model
,
nil
));
err
!=
nil
{
if
!
sendChatChunk
(
helper
.
GenerateStartEmptyResponse
(
responseId
,
createAt
,
model
,
nil
))
{
streamErr
=
types
.
NewOpenAIError
(
err
,
types
.
ErrorCodeBadResponse
,
http
.
StatusInternalServerError
)
return
false
return
false
}
}
sentStart
=
true
sentStart
=
true
...
@@ -186,8 +223,7 @@ func OaiResponsesToChatStreamHandler(c *gin.Context, info *relaycommon.RelayInfo
...
@@ -186,8 +223,7 @@ func OaiResponsesToChatStreamHandler(c *gin.Context, info *relaycommon.RelayInfo
},
},
},
},
}
}
if
err
:=
helper
.
ObjectData
(
c
,
chunk
);
err
!=
nil
{
if
!
sendChatChunk
(
chunk
)
{
streamErr
=
types
.
NewOpenAIError
(
err
,
types
.
ErrorCodeBadResponse
,
http
.
StatusInternalServerError
)
return
false
return
false
}
}
hasSentReasoningSummary
=
true
hasSentReasoningSummary
=
true
...
@@ -245,8 +281,7 @@ func OaiResponsesToChatStreamHandler(c *gin.Context, info *relaycommon.RelayInfo
...
@@ -245,8 +281,7 @@ func OaiResponsesToChatStreamHandler(c *gin.Context, info *relaycommon.RelayInfo
},
},
},
},
}
}
if
err
:=
helper
.
ObjectData
(
c
,
chunk
);
err
!=
nil
{
if
!
sendChatChunk
(
chunk
)
{
streamErr
=
types
.
NewOpenAIError
(
err
,
types
.
ErrorCodeBadResponse
,
http
.
StatusInternalServerError
)
return
false
return
false
}
}
sawToolCall
=
true
sawToolCall
=
true
...
@@ -340,8 +375,7 @@ func OaiResponsesToChatStreamHandler(c *gin.Context, info *relaycommon.RelayInfo
...
@@ -340,8 +375,7 @@ func OaiResponsesToChatStreamHandler(c *gin.Context, info *relaycommon.RelayInfo
},
},
},
},
}
}
if
err
:=
helper
.
ObjectData
(
c
,
chunk
);
err
!=
nil
{
if
!
sendChatChunk
(
chunk
)
{
streamErr
=
types
.
NewOpenAIError
(
err
,
types
.
ErrorCodeBadResponse
,
http
.
StatusInternalServerError
)
return
false
return
false
}
}
}
}
...
@@ -436,13 +470,15 @@ func OaiResponsesToChatStreamHandler(c *gin.Context, info *relaycommon.RelayInfo
...
@@ -436,13 +470,15 @@ func OaiResponsesToChatStreamHandler(c *gin.Context, info *relaycommon.RelayInfo
return
false
return
false
}
}
if
!
sentStop
{
if
!
sentStop
{
if
info
.
RelayFormat
==
types
.
RelayFormatClaude
&&
info
.
ClaudeConvertInfo
!=
nil
{
info
.
ClaudeConvertInfo
.
Usage
=
usage
}
finishReason
:=
"stop"
finishReason
:=
"stop"
if
sawToolCall
&&
outputText
.
Len
()
==
0
{
if
sawToolCall
&&
outputText
.
Len
()
==
0
{
finishReason
=
"tool_calls"
finishReason
=
"tool_calls"
}
}
stop
:=
helper
.
GenerateStopResponse
(
responseId
,
createAt
,
model
,
finishReason
)
stop
:=
helper
.
GenerateStopResponse
(
responseId
,
createAt
,
model
,
finishReason
)
if
err
:=
helper
.
ObjectData
(
c
,
stop
);
err
!=
nil
{
if
!
sendChatChunk
(
stop
)
{
streamErr
=
types
.
NewOpenAIError
(
err
,
types
.
ErrorCodeBadResponse
,
http
.
StatusInternalServerError
)
return
false
return
false
}
}
sentStop
=
true
sentStop
=
true
...
@@ -473,26 +509,31 @@ func OaiResponsesToChatStreamHandler(c *gin.Context, info *relaycommon.RelayInfo
...
@@ -473,26 +509,31 @@ func OaiResponsesToChatStreamHandler(c *gin.Context, info *relaycommon.RelayInfo
}
}
if
!
sentStart
{
if
!
sentStart
{
if
err
:=
helper
.
ObjectData
(
c
,
helper
.
GenerateStartEmptyResponse
(
responseId
,
createAt
,
model
,
nil
));
err
!=
nil
{
if
!
sendChatChunk
(
helper
.
GenerateStartEmptyResponse
(
responseId
,
createAt
,
model
,
nil
))
{
return
nil
,
types
.
NewOpenAIError
(
err
,
types
.
ErrorCodeBadResponse
,
http
.
StatusInternalServerError
)
return
nil
,
streamErr
}
}
}
}
if
!
sentStop
{
if
!
sentStop
{
if
info
.
RelayFormat
==
types
.
RelayFormatClaude
&&
info
.
ClaudeConvertInfo
!=
nil
{
info
.
ClaudeConvertInfo
.
Usage
=
usage
}
finishReason
:=
"stop"
finishReason
:=
"stop"
if
sawToolCall
&&
outputText
.
Len
()
==
0
{
if
sawToolCall
&&
outputText
.
Len
()
==
0
{
finishReason
=
"tool_calls"
finishReason
=
"tool_calls"
}
}
stop
:=
helper
.
GenerateStopResponse
(
responseId
,
createAt
,
model
,
finishReason
)
stop
:=
helper
.
GenerateStopResponse
(
responseId
,
createAt
,
model
,
finishReason
)
if
err
:=
helper
.
ObjectData
(
c
,
stop
);
err
!=
nil
{
if
!
sendChatChunk
(
stop
)
{
return
nil
,
types
.
NewOpenAIError
(
err
,
types
.
ErrorCodeBadResponse
,
http
.
StatusInternalServerError
)
return
nil
,
streamErr
}
}
}
}
if
info
.
ShouldIncludeUsage
&&
usage
!=
nil
{
if
info
.
RelayFormat
==
types
.
RelayFormatOpenAI
&&
info
.
ShouldIncludeUsage
&&
usage
!=
nil
{
if
err
:=
helper
.
ObjectData
(
c
,
helper
.
GenerateFinalUsageResponse
(
responseId
,
createAt
,
model
,
*
usage
));
err
!=
nil
{
if
err
:=
helper
.
ObjectData
(
c
,
helper
.
GenerateFinalUsageResponse
(
responseId
,
createAt
,
model
,
*
usage
));
err
!=
nil
{
return
nil
,
types
.
NewOpenAIError
(
err
,
types
.
ErrorCodeBadResponse
,
http
.
StatusInternalServerError
)
return
nil
,
types
.
NewOpenAIError
(
err
,
types
.
ErrorCodeBadResponse
,
http
.
StatusInternalServerError
)
}
}
}
}
helper
.
Done
(
c
)
if
info
.
RelayFormat
==
types
.
RelayFormatOpenAI
{
helper
.
Done
(
c
)
}
return
usage
,
nil
return
usage
,
nil
}
}
relay/claude_handler.go
View file @
6c28de89
...
@@ -110,6 +110,23 @@ func ClaudeHelper(c *gin.Context, info *relaycommon.RelayInfo) (newAPIError *typ
...
@@ -110,6 +110,23 @@ func ClaudeHelper(c *gin.Context, info *relaycommon.RelayInfo) (newAPIError *typ
}
}
}
}
if
!
model_setting
.
GetGlobalSettings
()
.
PassThroughRequestEnabled
&&
!
info
.
ChannelSetting
.
PassThroughBodyEnabled
&&
service
.
ShouldChatCompletionsUseResponsesGlobal
(
info
.
ChannelId
,
info
.
ChannelType
,
info
.
OriginModelName
)
{
openAIRequest
,
convErr
:=
service
.
ClaudeToOpenAIRequest
(
*
request
,
info
)
if
convErr
!=
nil
{
return
types
.
NewError
(
convErr
,
types
.
ErrorCodeConvertRequestFailed
,
types
.
ErrOptionWithSkipRetry
())
}
usage
,
newApiErr
:=
chatCompletionsViaResponses
(
c
,
info
,
adaptor
,
openAIRequest
)
if
newApiErr
!=
nil
{
return
newApiErr
}
service
.
PostClaudeConsumeQuota
(
c
,
info
,
usage
)
return
nil
}
var
requestBody
io
.
Reader
var
requestBody
io
.
Reader
if
model_setting
.
GetGlobalSettings
()
.
PassThroughRequestEnabled
||
info
.
ChannelSetting
.
PassThroughBodyEnabled
{
if
model_setting
.
GetGlobalSettings
()
.
PassThroughRequestEnabled
||
info
.
ChannelSetting
.
PassThroughBodyEnabled
{
body
,
err
:=
common
.
GetRequestBody
(
c
)
body
,
err
:=
common
.
GetRequestBody
(
c
)
...
...
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