Enhance response and request handling in translators

- Refactored response handling to process multiple content parts effectively.
- Improved `tool_calls` structure with unique ID generation and enhanced mapping logic.
- Simplified `SystemInstruction` and tool message parsing in requests for better accuracy.
- Enhanced handling of function calls and tool responses with improved data integration.
This commit is contained in:
Luis Pater
2025-07-10 22:26:04 +08:00
parent ef68a97526
commit fa8d94971f
2 changed files with 91 additions and 45 deletions

View File

@@ -24,6 +24,39 @@ func PrepareRequest(rawJson []byte) (string, *client.Content, []client.Content,
contents := make([]client.Content, 0) contents := make([]client.Content, 0)
var systemInstruction *client.Content var systemInstruction *client.Content
messagesResult := gjson.GetBytes(rawJson, "messages") messagesResult := gjson.GetBytes(rawJson, "messages")
toolItems := make(map[string]*client.FunctionResponse)
if messagesResult.IsArray() {
messagesResults := messagesResult.Array()
for i := 0; i < len(messagesResults); i++ {
messageResult := messagesResults[i]
roleResult := messageResult.Get("role")
if roleResult.Type != gjson.String {
continue
}
contentResult := messageResult.Get("content")
if roleResult.String() == "tool" {
toolCallID := messageResult.Get("tool_call_id").String()
if toolCallID != "" {
var responseData string
if contentResult.Type == gjson.String {
responseData = contentResult.String()
} else if contentResult.IsObject() && contentResult.Get("type").String() == "text" {
responseData = contentResult.Get("text").String()
}
// drop the timestamp from the tool call ID
toolCallIDs := strings.Split(toolCallID, "-")
strings.Join(toolCallIDs, "-")
newToolCallID := strings.Join(toolCallIDs[:len(toolCallIDs)-1], "-")
functionResponse := client.FunctionResponse{Name: newToolCallID, Response: map[string]interface{}{"result": responseData}}
toolItems[toolCallID] = &functionResponse
}
}
}
}
if messagesResult.IsArray() { if messagesResult.IsArray() {
messagesResults := messagesResult.Array() messagesResults := messagesResult.Array()
for i := 0; i < len(messagesResults); i++ { for i := 0; i < len(messagesResults); i++ {
@@ -97,39 +130,43 @@ func PrepareRequest(rawJson []byte) (string, *client.Content, []client.Content,
contents = append(contents, client.Content{Role: "model", Parts: []client.Part{{Text: contentResult.String()}}}) contents = append(contents, client.Content{Role: "model", Parts: []client.Part{{Text: contentResult.String()}}})
} else if !contentResult.Exists() || contentResult.Type == gjson.Null { } else if !contentResult.Exists() || contentResult.Type == gjson.Null {
// Handle tool calls made by the assistant. // Handle tool calls made by the assistant.
functionIDs := make([]string, 0)
toolCallsResult := messageResult.Get("tool_calls") toolCallsResult := messageResult.Get("tool_calls")
if toolCallsResult.IsArray() { if toolCallsResult.IsArray() {
parts := make([]client.Part, 0)
tcsResult := toolCallsResult.Array() tcsResult := toolCallsResult.Array()
for j := 0; j < len(tcsResult); j++ { for j := 0; j < len(tcsResult); j++ {
tcResult := tcsResult[j] tcResult := tcsResult[j]
functionID := tcResult.Get("id").String()
functionIDs = append(functionIDs, functionID)
functionName := tcResult.Get("function.name").String() functionName := tcResult.Get("function.name").String()
functionArgs := tcResult.Get("function.arguments").String() functionArgs := tcResult.Get("function.arguments").String()
var args map[string]any var args map[string]any
if err := json.Unmarshal([]byte(functionArgs), &args); err == nil { if err := json.Unmarshal([]byte(functionArgs), &args); err == nil {
contents = append(contents, client.Content{ parts = append(parts, client.Part{
Role: "model", Parts: []client.Part{{
FunctionCall: &client.FunctionCall{ FunctionCall: &client.FunctionCall{
Name: functionName, Name: functionName,
Args: args, Args: args,
}, },
}},
}) })
} }
} }
if len(parts) > 0 {
contents = append(contents, client.Content{
Role: "model", Parts: parts,
})
toolParts := make([]client.Part, 0)
for _, functionID := range functionIDs {
if functionResponse, ok := toolItems[functionID]; ok {
toolParts = append(toolParts, client.Part{FunctionResponse: functionResponse})
} }
} }
// Tool messages contain the output of a tool call. contents = append(contents, client.Content{Role: "tool", Parts: toolParts})
case "tool": }
toolCallID := messageResult.Get("tool_call_id").String()
if toolCallID != "" {
var responseData string
if contentResult.Type == gjson.String {
responseData = contentResult.String()
} else if contentResult.IsObject() && contentResult.Get("type").String() == "text" {
responseData = contentResult.Get("text").String()
} }
functionResponse := client.FunctionResponse{Name: toolCallID, Response: map[string]interface{}{"result": responseData}}
contents = append(contents, client.Content{Role: "tool", Parts: []client.Part{{FunctionResponse: &functionResponse}}})
} }
} }
} }

View File

@@ -1,6 +1,7 @@
package translator package translator
import ( import (
"fmt"
"time" "time"
"github.com/tidwall/gjson" "github.com/tidwall/gjson"
@@ -62,7 +63,11 @@ func ConvertCliToOpenAI(rawJson []byte, unixTimestamp int64, isGlAPIKey bool) st
} }
// Process the main content part of the response. // Process the main content part of the response.
partResult := gjson.GetBytes(rawJson, "response.candidates.0.content.parts.0") partsResult := gjson.GetBytes(rawJson, "response.candidates.0.content.parts")
if partsResult.IsArray() {
partResults := partsResult.Array()
for i := 0; i < len(partResults); i++ {
partResult := partResults[i]
partTextResult := partResult.Get("text") partTextResult := partResult.Get("text")
functionCallResult := partResult.Get("functionCall") functionCallResult := partResult.Get("functionCall")
@@ -76,18 +81,22 @@ func ConvertCliToOpenAI(rawJson []byte, unixTimestamp int64, isGlAPIKey bool) st
template, _ = sjson.Set(template, "choices.0.delta.role", "assistant") template, _ = sjson.Set(template, "choices.0.delta.role", "assistant")
} else if functionCallResult.Exists() { } else if functionCallResult.Exists() {
// Handle function call content. // Handle function call content.
functionCallTemplate := `[{"id": "","type": "function","function": {"name": "","arguments": ""}}]` toolCallsResult := gjson.Get(template, "choices.0.delta.tool_calls")
if !toolCallsResult.Exists() || !toolCallsResult.IsArray() {
template, _ = sjson.SetRaw(template, "choices.0.delta.tool_calls", `[]`)
}
functionCallTemplate := `{"id": "","type": "function","function": {"name": "","arguments": ""}}`
fcName := functionCallResult.Get("name").String() fcName := functionCallResult.Get("name").String()
functionCallTemplate, _ = sjson.Set(functionCallTemplate, "0.id", fcName) functionCallTemplate, _ = sjson.Set(functionCallTemplate, "id", fmt.Sprintf("%s-%d", fcName, time.Now().UnixNano()))
functionCallTemplate, _ = sjson.Set(functionCallTemplate, "0.function.name", fcName) functionCallTemplate, _ = sjson.Set(functionCallTemplate, "function.name", fcName)
if fcArgsResult := functionCallResult.Get("args"); fcArgsResult.Exists() { if fcArgsResult := functionCallResult.Get("args"); fcArgsResult.Exists() {
functionCallTemplate, _ = sjson.Set(functionCallTemplate, "0.function.arguments", fcArgsResult.Raw) functionCallTemplate, _ = sjson.Set(functionCallTemplate, "function.arguments", fcArgsResult.Raw)
} }
template, _ = sjson.Set(template, "choices.0.delta.role", "assistant") template, _ = sjson.Set(template, "choices.0.delta.role", "assistant")
template, _ = sjson.SetRaw(template, "choices.0.delta.tool_calls", functionCallTemplate) template, _ = sjson.SetRaw(template, "choices.0.message.tool_calls.-1", functionCallTemplate)
} else { }
// If no usable content is found, return an empty string. }
return ""
} }
return template return template
@@ -163,7 +172,7 @@ func ConvertCliToOpenAINonStream(rawJson []byte, unixTimestamp int64, isGlAPIKey
} }
functionCallItemTemplate := `{"id": "","type": "function","function": {"name": "","arguments": ""}}` functionCallItemTemplate := `{"id": "","type": "function","function": {"name": "","arguments": ""}}`
fcName := functionCallResult.Get("name").String() fcName := functionCallResult.Get("name").String()
functionCallItemTemplate, _ = sjson.Set(functionCallItemTemplate, "id", fcName) functionCallItemTemplate, _ = sjson.Set(functionCallItemTemplate, "id", fmt.Sprintf("%s-%d", fcName, time.Now().UnixNano()))
functionCallItemTemplate, _ = sjson.Set(functionCallItemTemplate, "function.name", fcName) functionCallItemTemplate, _ = sjson.Set(functionCallItemTemplate, "function.name", fcName)
if fcArgsResult := functionCallResult.Get("args"); fcArgsResult.Exists() { if fcArgsResult := functionCallResult.Get("args"); fcArgsResult.Exists() {
functionCallItemTemplate, _ = sjson.Set(functionCallItemTemplate, "function.arguments", fcArgsResult.Raw) functionCallItemTemplate, _ = sjson.Set(functionCallItemTemplate, "function.arguments", fcArgsResult.Raw)