|
@@ -44,24 +44,26 @@ func ClaudeToOpenAIRequest(claudeRequest dto.ClaudeRequest) (*dto.GeneralOpenAIR
|
|
|
openAIMessages := make([]dto.Message, 0)
|
|
openAIMessages := make([]dto.Message, 0)
|
|
|
|
|
|
|
|
// Add system message if present
|
|
// Add system message if present
|
|
|
- if claudeRequest.IsStringSystem() {
|
|
|
|
|
- openAIMessage := dto.Message{
|
|
|
|
|
- Role: "system",
|
|
|
|
|
- }
|
|
|
|
|
- openAIMessage.SetStringContent(claudeRequest.GetStringSystem())
|
|
|
|
|
- openAIMessages = append(openAIMessages, openAIMessage)
|
|
|
|
|
- } else {
|
|
|
|
|
- systems := claudeRequest.ParseSystem()
|
|
|
|
|
- if len(systems) > 0 {
|
|
|
|
|
- systemStr := ""
|
|
|
|
|
|
|
+ if claudeRequest.System != nil {
|
|
|
|
|
+ if claudeRequest.IsStringSystem() {
|
|
|
openAIMessage := dto.Message{
|
|
openAIMessage := dto.Message{
|
|
|
Role: "system",
|
|
Role: "system",
|
|
|
}
|
|
}
|
|
|
- for _, system := range systems {
|
|
|
|
|
- systemStr += system.Type
|
|
|
|
|
- }
|
|
|
|
|
- openAIMessage.SetStringContent(systemStr)
|
|
|
|
|
|
|
+ openAIMessage.SetStringContent(claudeRequest.GetStringSystem())
|
|
|
openAIMessages = append(openAIMessages, openAIMessage)
|
|
openAIMessages = append(openAIMessages, openAIMessage)
|
|
|
|
|
+ } else {
|
|
|
|
|
+ systems := claudeRequest.ParseSystem()
|
|
|
|
|
+ if len(systems) > 0 {
|
|
|
|
|
+ systemStr := ""
|
|
|
|
|
+ openAIMessage := dto.Message{
|
|
|
|
|
+ Role: "system",
|
|
|
|
|
+ }
|
|
|
|
|
+ for _, system := range systems {
|
|
|
|
|
+ systemStr += system.Type
|
|
|
|
|
+ }
|
|
|
|
|
+ openAIMessage.SetStringContent(systemStr)
|
|
|
|
|
+ openAIMessages = append(openAIMessages, openAIMessage)
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
for _, claudeMessage := range claudeRequest.Messages {
|
|
for _, claudeMessage := range claudeRequest.Messages {
|
|
@@ -100,7 +102,8 @@ func ClaudeToOpenAIRequest(claudeRequest dto.ClaudeRequest) (*dto.GeneralOpenAIR
|
|
|
mediaMessages = append(mediaMessages, mediaMessage)
|
|
mediaMessages = append(mediaMessages, mediaMessage)
|
|
|
case "tool_use":
|
|
case "tool_use":
|
|
|
toolCall := dto.ToolCallRequest{
|
|
toolCall := dto.ToolCallRequest{
|
|
|
- ID: mediaMsg.Id,
|
|
|
|
|
|
|
+ ID: mediaMsg.Id,
|
|
|
|
|
+ Type: "function",
|
|
|
Function: dto.FunctionRequest{
|
|
Function: dto.FunctionRequest{
|
|
|
Name: mediaMsg.Name,
|
|
Name: mediaMsg.Name,
|
|
|
Arguments: toJSONString(mediaMsg.Input),
|
|
Arguments: toJSONString(mediaMsg.Input),
|
|
@@ -111,20 +114,33 @@ func ClaudeToOpenAIRequest(claudeRequest dto.ClaudeRequest) (*dto.GeneralOpenAIR
|
|
|
// Add tool result as a separate message
|
|
// Add tool result as a separate message
|
|
|
oaiToolMessage := dto.Message{
|
|
oaiToolMessage := dto.Message{
|
|
|
Role: "tool",
|
|
Role: "tool",
|
|
|
|
|
+ Name: &mediaMsg.Name,
|
|
|
ToolCallId: mediaMsg.ToolUseId,
|
|
ToolCallId: mediaMsg.ToolUseId,
|
|
|
}
|
|
}
|
|
|
- oaiToolMessage.Content = mediaMsg.Content
|
|
|
|
|
|
|
+ //oaiToolMessage.SetStringContent(*mediaMsg.GetMediaContent().Text)
|
|
|
|
|
+ if mediaMsg.IsStringContent() {
|
|
|
|
|
+ oaiToolMessage.SetStringContent(mediaMsg.GetStringContent())
|
|
|
|
|
+ } else {
|
|
|
|
|
+ mediaContents := mediaMsg.ParseMediaContent()
|
|
|
|
|
+ if len(mediaContents) > 0 && mediaContents[0].Text != nil {
|
|
|
|
|
+ oaiToolMessage.SetStringContent(*mediaContents[0].Text)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ openAIMessages = append(openAIMessages, oaiToolMessage)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- openAIMessage.SetMediaContent(mediaMessages)
|
|
|
|
|
|
|
+ if len(mediaMessages) > 0 {
|
|
|
|
|
+ openAIMessage.SetMediaContent(mediaMessages)
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
if len(toolCalls) > 0 {
|
|
if len(toolCalls) > 0 {
|
|
|
openAIMessage.SetToolCalls(toolCalls)
|
|
openAIMessage.SetToolCalls(toolCalls)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- openAIMessages = append(openAIMessages, openAIMessage)
|
|
|
|
|
|
|
+ if len(openAIMessage.ParseContent()) > 0 {
|
|
|
|
|
+ openAIMessages = append(openAIMessages, openAIMessage)
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
openAIRequest.Messages = openAIMessages
|
|
openAIRequest.Messages = openAIMessages
|
|
@@ -154,22 +170,35 @@ func ClaudeErrorToOpenAIError(claudeError *dto.ClaudeErrorWithStatusCode) *dto.O
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+func generateStopBlock(index int) *dto.ClaudeResponse {
|
|
|
|
|
+ return &dto.ClaudeResponse{
|
|
|
|
|
+ Type: "content_block_stop",
|
|
|
|
|
+ Index: common.GetPointer[int](index),
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
func StreamResponseOpenAI2Claude(openAIResponse *dto.ChatCompletionsStreamResponse, info *relaycommon.RelayInfo) []*dto.ClaudeResponse {
|
|
func StreamResponseOpenAI2Claude(openAIResponse *dto.ChatCompletionsStreamResponse, info *relaycommon.RelayInfo) []*dto.ClaudeResponse {
|
|
|
var claudeResponses []*dto.ClaudeResponse
|
|
var claudeResponses []*dto.ClaudeResponse
|
|
|
- if info.ResponseTimes == 1 {
|
|
|
|
|
- claudeResponses = append(claudeResponses, &dto.ClaudeResponse{
|
|
|
|
|
- Type: "message_start",
|
|
|
|
|
- Message: &dto.ClaudeMediaMessage{
|
|
|
|
|
- Id: openAIResponse.Id,
|
|
|
|
|
- Model: openAIResponse.Model,
|
|
|
|
|
- Type: "message",
|
|
|
|
|
- Role: "assistant",
|
|
|
|
|
- Usage: &dto.ClaudeUsage{
|
|
|
|
|
- InputTokens: info.PromptTokens,
|
|
|
|
|
- OutputTokens: 0,
|
|
|
|
|
- },
|
|
|
|
|
|
|
+ if info.SendResponseCount == 1 {
|
|
|
|
|
+ msg := &dto.ClaudeMediaMessage{
|
|
|
|
|
+ Id: openAIResponse.Id,
|
|
|
|
|
+ Model: openAIResponse.Model,
|
|
|
|
|
+ Type: "message",
|
|
|
|
|
+ Role: "assistant",
|
|
|
|
|
+ Usage: &dto.ClaudeUsage{
|
|
|
|
|
+ InputTokens: info.PromptTokens,
|
|
|
|
|
+ OutputTokens: 0,
|
|
|
},
|
|
},
|
|
|
|
|
+ }
|
|
|
|
|
+ msg.SetContent(make([]any, 0))
|
|
|
|
|
+ claudeResponses = append(claudeResponses, &dto.ClaudeResponse{
|
|
|
|
|
+ Type: "message_start",
|
|
|
|
|
+ Message: msg,
|
|
|
})
|
|
})
|
|
|
|
|
+ claudeResponses = append(claudeResponses)
|
|
|
|
|
+ //claudeResponses = append(claudeResponses, &dto.ClaudeResponse{
|
|
|
|
|
+ // Type: "ping",
|
|
|
|
|
+ //})
|
|
|
if openAIResponse.IsToolCall() {
|
|
if openAIResponse.IsToolCall() {
|
|
|
resp := &dto.ClaudeResponse{
|
|
resp := &dto.ClaudeResponse{
|
|
|
Type: "content_block_start",
|
|
Type: "content_block_start",
|
|
@@ -192,23 +221,18 @@ func StreamResponseOpenAI2Claude(openAIResponse *dto.ChatCompletionsStreamRespon
|
|
|
resp.SetIndex(0)
|
|
resp.SetIndex(0)
|
|
|
claudeResponses = append(claudeResponses, resp)
|
|
claudeResponses = append(claudeResponses, resp)
|
|
|
}
|
|
}
|
|
|
- claudeResponses = append(claudeResponses, &dto.ClaudeResponse{
|
|
|
|
|
- Type: "ping",
|
|
|
|
|
- })
|
|
|
|
|
return claudeResponses
|
|
return claudeResponses
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if len(openAIResponse.Choices) == 0 {
|
|
if len(openAIResponse.Choices) == 0 {
|
|
|
// no choices
|
|
// no choices
|
|
|
// TODO: handle this case
|
|
// TODO: handle this case
|
|
|
|
|
+ return claudeResponses
|
|
|
} else {
|
|
} else {
|
|
|
chosenChoice := openAIResponse.Choices[0]
|
|
chosenChoice := openAIResponse.Choices[0]
|
|
|
if chosenChoice.FinishReason != nil && *chosenChoice.FinishReason != "" {
|
|
if chosenChoice.FinishReason != nil && *chosenChoice.FinishReason != "" {
|
|
|
// should be done
|
|
// should be done
|
|
|
- claudeResponses = append(claudeResponses, &dto.ClaudeResponse{
|
|
|
|
|
- Type: "content_block_stop",
|
|
|
|
|
- Index: common.GetPointer[int](0),
|
|
|
|
|
- })
|
|
|
|
|
|
|
+ claudeResponses = append(claudeResponses, generateStopBlock(info.ClaudeConvertInfo.Index))
|
|
|
if openAIResponse.Usage != nil {
|
|
if openAIResponse.Usage != nil {
|
|
|
claudeResponses = append(claudeResponses, &dto.ClaudeResponse{
|
|
claudeResponses = append(claudeResponses, &dto.ClaudeResponse{
|
|
|
Type: "message_delta",
|
|
Type: "message_delta",
|
|
@@ -229,18 +253,35 @@ func StreamResponseOpenAI2Claude(openAIResponse *dto.ChatCompletionsStreamRespon
|
|
|
claudeResponse.SetIndex(0)
|
|
claudeResponse.SetIndex(0)
|
|
|
claudeResponse.Type = "content_block_delta"
|
|
claudeResponse.Type = "content_block_delta"
|
|
|
if len(chosenChoice.Delta.ToolCalls) > 0 {
|
|
if len(chosenChoice.Delta.ToolCalls) > 0 {
|
|
|
|
|
+ if info.ClaudeConvertInfo.LastMessagesType == relaycommon.LastMessageTypeText {
|
|
|
|
|
+ claudeResponses = append(claudeResponses, generateStopBlock(info.ClaudeConvertInfo.Index))
|
|
|
|
|
+ info.ClaudeConvertInfo.Index++
|
|
|
|
|
+ claudeResponses = append(claudeResponses, &dto.ClaudeResponse{
|
|
|
|
|
+ Index: &info.ClaudeConvertInfo.Index,
|
|
|
|
|
+ Type: "content_block_start",
|
|
|
|
|
+ ContentBlock: &dto.ClaudeMediaMessage{
|
|
|
|
|
+ Id: openAIResponse.GetFirstToolCall().ID,
|
|
|
|
|
+ Type: "tool_use",
|
|
|
|
|
+ Name: openAIResponse.GetFirstToolCall().Function.Name,
|
|
|
|
|
+ Input: map[string]interface{}{},
|
|
|
|
|
+ },
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+ info.ClaudeConvertInfo.LastMessagesType = relaycommon.LastMessageTypeTools
|
|
|
// tools delta
|
|
// tools delta
|
|
|
claudeResponse.Delta = &dto.ClaudeMediaMessage{
|
|
claudeResponse.Delta = &dto.ClaudeMediaMessage{
|
|
|
Type: "input_json_delta",
|
|
Type: "input_json_delta",
|
|
|
- PartialJson: chosenChoice.Delta.ToolCalls[0].Function.Arguments,
|
|
|
|
|
|
|
+ PartialJson: &chosenChoice.Delta.ToolCalls[0].Function.Arguments,
|
|
|
}
|
|
}
|
|
|
} else {
|
|
} else {
|
|
|
|
|
+ info.ClaudeConvertInfo.LastMessagesType = relaycommon.LastMessageTypeText
|
|
|
// text delta
|
|
// text delta
|
|
|
claudeResponse.Delta = &dto.ClaudeMediaMessage{
|
|
claudeResponse.Delta = &dto.ClaudeMediaMessage{
|
|
|
Type: "text_delta",
|
|
Type: "text_delta",
|
|
|
Text: common.GetPointer[string](chosenChoice.Delta.GetContentString()),
|
|
Text: common.GetPointer[string](chosenChoice.Delta.GetContentString()),
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+ claudeResponse.Index = &info.ClaudeConvertInfo.Index
|
|
|
claudeResponses = append(claudeResponses, &claudeResponse)
|
|
claudeResponses = append(claudeResponses, &claudeResponse)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|