mirror of
https://github.com/router-for-me/CLIProxyAPI.git
synced 2026-02-18 20:30:51 +08:00
Merge remote-tracking branch 'upstream/main' into feature/ampcode-alias
This commit is contained in:
@@ -11,7 +11,6 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/router-for-me/CLIProxyAPI/v6/internal/misc"
|
||||
"github.com/router-for-me/CLIProxyAPI/v6/internal/thinking"
|
||||
"github.com/tidwall/gjson"
|
||||
"github.com/tidwall/sjson"
|
||||
@@ -21,12 +20,12 @@ import (
|
||||
// It extracts the model name, system instruction, message contents, and tool declarations
|
||||
// from the raw JSON request and returns them in the format expected by the internal client.
|
||||
// The function performs the following transformations:
|
||||
// 1. Sets up a template with the model name and Codex instructions
|
||||
// 2. Processes system messages and converts them to input content
|
||||
// 3. Transforms message contents (text, tool_use, tool_result) to appropriate formats
|
||||
// 1. Sets up a template with the model name and empty instructions field
|
||||
// 2. Processes system messages and converts them to developer input content
|
||||
// 3. Transforms message contents (text, image, tool_use, tool_result) to appropriate formats
|
||||
// 4. Converts tools declarations to the expected format
|
||||
// 5. Adds additional configuration parameters for the Codex API
|
||||
// 6. Prepends a special instruction message to override system instructions
|
||||
// 6. Maps Claude thinking configuration to Codex reasoning settings
|
||||
//
|
||||
// Parameters:
|
||||
// - modelName: The name of the model to use for the request
|
||||
@@ -37,13 +36,9 @@ import (
|
||||
// - []byte: The transformed request data in internal client format
|
||||
func ConvertClaudeRequestToCodex(modelName string, inputRawJSON []byte, _ bool) []byte {
|
||||
rawJSON := bytes.Clone(inputRawJSON)
|
||||
userAgent := misc.ExtractCodexUserAgent(rawJSON)
|
||||
|
||||
template := `{"model":"","instructions":"","input":[]}`
|
||||
|
||||
_, instructions := misc.CodexInstructionsForModel(modelName, "", userAgent)
|
||||
template, _ = sjson.Set(template, "instructions", instructions)
|
||||
|
||||
rootResult := gjson.ParseBytes(rawJSON)
|
||||
template, _ = sjson.Set(template, "model", modelName)
|
||||
|
||||
@@ -240,26 +235,6 @@ func ConvertClaudeRequestToCodex(modelName string, inputRawJSON []byte, _ bool)
|
||||
template, _ = sjson.Set(template, "store", false)
|
||||
template, _ = sjson.Set(template, "include", []string{"reasoning.encrypted_content"})
|
||||
|
||||
// Add a first message to ignore system instructions and ensure proper execution.
|
||||
if misc.GetCodexInstructionsEnabled() {
|
||||
inputResult := gjson.Get(template, "input")
|
||||
if inputResult.Exists() && inputResult.IsArray() {
|
||||
inputResults := inputResult.Array()
|
||||
newInput := "[]"
|
||||
for i := 0; i < len(inputResults); i++ {
|
||||
if i == 0 {
|
||||
firstText := inputResults[i].Get("content.0.text")
|
||||
firstInstructions := "EXECUTE ACCORDING TO THE FOLLOWING INSTRUCTIONS!!!"
|
||||
if firstText.Exists() && firstText.String() != firstInstructions {
|
||||
newInput, _ = sjson.SetRaw(newInput, "-1", `{"type":"message","role":"user","content":[{"type":"input_text","text":"EXECUTE ACCORDING TO THE FOLLOWING INSTRUCTIONS!!!"}]}`)
|
||||
}
|
||||
}
|
||||
newInput, _ = sjson.SetRaw(newInput, "-1", inputResults[i].Raw)
|
||||
}
|
||||
template, _ = sjson.SetRaw(template, "input", newInput)
|
||||
}
|
||||
}
|
||||
|
||||
return []byte(template)
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,6 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/router-for-me/CLIProxyAPI/v6/internal/misc"
|
||||
"github.com/router-for-me/CLIProxyAPI/v6/internal/thinking"
|
||||
"github.com/router-for-me/CLIProxyAPI/v6/internal/util"
|
||||
"github.com/tidwall/gjson"
|
||||
@@ -39,14 +38,9 @@ import (
|
||||
// - []byte: The transformed request data in Codex API format
|
||||
func ConvertGeminiRequestToCodex(modelName string, inputRawJSON []byte, _ bool) []byte {
|
||||
rawJSON := bytes.Clone(inputRawJSON)
|
||||
userAgent := misc.ExtractCodexUserAgent(rawJSON)
|
||||
// Base template
|
||||
out := `{"model":"","instructions":"","input":[]}`
|
||||
|
||||
// Inject standard Codex instructions
|
||||
_, instructions := misc.CodexInstructionsForModel(modelName, "", userAgent)
|
||||
out, _ = sjson.Set(out, "instructions", instructions)
|
||||
|
||||
root := gjson.ParseBytes(rawJSON)
|
||||
|
||||
// Pre-compute tool name shortening map from declared functionDeclarations
|
||||
|
||||
@@ -12,7 +12,6 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/router-for-me/CLIProxyAPI/v6/internal/misc"
|
||||
"github.com/tidwall/gjson"
|
||||
"github.com/tidwall/sjson"
|
||||
)
|
||||
@@ -31,7 +30,6 @@ import (
|
||||
// - []byte: The transformed request data in OpenAI Responses API format
|
||||
func ConvertOpenAIRequestToCodex(modelName string, inputRawJSON []byte, stream bool) []byte {
|
||||
rawJSON := bytes.Clone(inputRawJSON)
|
||||
userAgent := misc.ExtractCodexUserAgent(rawJSON)
|
||||
// Start with empty JSON object
|
||||
out := `{"instructions":""}`
|
||||
|
||||
@@ -97,10 +95,6 @@ func ConvertOpenAIRequestToCodex(modelName string, inputRawJSON []byte, stream b
|
||||
|
||||
// Extract system instructions from first system message (string or text object)
|
||||
messages := gjson.GetBytes(rawJSON, "messages")
|
||||
_, instructions := misc.CodexInstructionsForModel(modelName, "", userAgent)
|
||||
if misc.GetCodexInstructionsEnabled() {
|
||||
out, _ = sjson.Set(out, "instructions", instructions)
|
||||
}
|
||||
// if messages.IsArray() {
|
||||
// arr := messages.Array()
|
||||
// for i := 0; i < len(arr); i++ {
|
||||
|
||||
@@ -2,18 +2,14 @@ package responses
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strconv"
|
||||
"strings"
|
||||
"fmt"
|
||||
|
||||
"github.com/router-for-me/CLIProxyAPI/v6/internal/misc"
|
||||
"github.com/tidwall/gjson"
|
||||
"github.com/tidwall/sjson"
|
||||
)
|
||||
|
||||
func ConvertOpenAIResponsesRequestToCodex(modelName string, inputRawJSON []byte, _ bool) []byte {
|
||||
rawJSON := bytes.Clone(inputRawJSON)
|
||||
userAgent := misc.ExtractCodexUserAgent(rawJSON)
|
||||
rawJSON = misc.StripCodexUserAgent(rawJSON)
|
||||
|
||||
rawJSON, _ = sjson.SetBytes(rawJSON, "stream", true)
|
||||
rawJSON, _ = sjson.SetBytes(rawJSON, "store", false)
|
||||
@@ -26,87 +22,31 @@ func ConvertOpenAIResponsesRequestToCodex(modelName string, inputRawJSON []byte,
|
||||
rawJSON, _ = sjson.DeleteBytes(rawJSON, "top_p")
|
||||
rawJSON, _ = sjson.DeleteBytes(rawJSON, "service_tier")
|
||||
|
||||
originalInstructions := ""
|
||||
originalInstructionsText := ""
|
||||
originalInstructionsResult := gjson.GetBytes(rawJSON, "instructions")
|
||||
if originalInstructionsResult.Exists() {
|
||||
originalInstructions = originalInstructionsResult.Raw
|
||||
originalInstructionsText = originalInstructionsResult.String()
|
||||
}
|
||||
|
||||
hasOfficialInstructions, instructions := misc.CodexInstructionsForModel(modelName, originalInstructionsResult.String(), userAgent)
|
||||
|
||||
inputResult := gjson.GetBytes(rawJSON, "input")
|
||||
var inputResults []gjson.Result
|
||||
if inputResult.Exists() {
|
||||
if inputResult.IsArray() {
|
||||
inputResults = inputResult.Array()
|
||||
} else if inputResult.Type == gjson.String {
|
||||
newInput := `[{"type":"message","role":"user","content":[{"type":"input_text","text":""}]}]`
|
||||
newInput, _ = sjson.SetRaw(newInput, "0.content.0.text", inputResult.Raw)
|
||||
inputResults = gjson.Parse(newInput).Array()
|
||||
}
|
||||
} else {
|
||||
inputResults = []gjson.Result{}
|
||||
}
|
||||
|
||||
extractedSystemInstructions := false
|
||||
if originalInstructions == "" && len(inputResults) > 0 {
|
||||
for _, item := range inputResults {
|
||||
if strings.EqualFold(item.Get("role").String(), "system") {
|
||||
var builder strings.Builder
|
||||
if content := item.Get("content"); content.Exists() && content.IsArray() {
|
||||
content.ForEach(func(_, contentItem gjson.Result) bool {
|
||||
text := contentItem.Get("text").String()
|
||||
if builder.Len() > 0 && text != "" {
|
||||
builder.WriteByte('\n')
|
||||
}
|
||||
builder.WriteString(text)
|
||||
return true
|
||||
})
|
||||
}
|
||||
originalInstructionsText = builder.String()
|
||||
originalInstructions = strconv.Quote(originalInstructionsText)
|
||||
extractedSystemInstructions = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if hasOfficialInstructions {
|
||||
newInput := "[]"
|
||||
for _, item := range inputResults {
|
||||
newInput, _ = sjson.SetRaw(newInput, "-1", item.Raw)
|
||||
}
|
||||
rawJSON, _ = sjson.SetRawBytes(rawJSON, "input", []byte(newInput))
|
||||
return rawJSON
|
||||
}
|
||||
// log.Debugf("instructions not matched, %s\n", originalInstructions)
|
||||
|
||||
if len(inputResults) > 0 {
|
||||
newInput := "[]"
|
||||
firstMessageHandled := false
|
||||
for _, item := range inputResults {
|
||||
if extractedSystemInstructions && strings.EqualFold(item.Get("role").String(), "system") {
|
||||
continue
|
||||
}
|
||||
if !firstMessageHandled {
|
||||
firstText := item.Get("content.0.text")
|
||||
firstInstructions := "EXECUTE ACCORDING TO THE FOLLOWING INSTRUCTIONS!!!"
|
||||
if firstText.Exists() && firstText.String() != firstInstructions {
|
||||
firstTextTemplate := `{"type":"message","role":"user","content":[{"type":"input_text","text":"EXECUTE ACCORDING TO THE FOLLOWING INSTRUCTIONS!!!"}]}`
|
||||
firstTextTemplate, _ = sjson.Set(firstTextTemplate, "content.1.text", originalInstructionsText)
|
||||
firstTextTemplate, _ = sjson.Set(firstTextTemplate, "content.1.type", "input_text")
|
||||
newInput, _ = sjson.SetRaw(newInput, "-1", firstTextTemplate)
|
||||
}
|
||||
firstMessageHandled = true
|
||||
}
|
||||
newInput, _ = sjson.SetRaw(newInput, "-1", item.Raw)
|
||||
}
|
||||
rawJSON, _ = sjson.SetRawBytes(rawJSON, "input", []byte(newInput))
|
||||
}
|
||||
|
||||
rawJSON, _ = sjson.SetBytes(rawJSON, "instructions", instructions)
|
||||
// Convert role "system" to "developer" in input array to comply with Codex API requirements.
|
||||
rawJSON = convertSystemRoleToDeveloper(rawJSON)
|
||||
|
||||
return rawJSON
|
||||
}
|
||||
|
||||
// convertSystemRoleToDeveloper traverses the input array and converts any message items
|
||||
// with role "system" to role "developer". This is necessary because Codex API does not
|
||||
// accept "system" role in the input array.
|
||||
func convertSystemRoleToDeveloper(rawJSON []byte) []byte {
|
||||
inputResult := gjson.GetBytes(rawJSON, "input")
|
||||
if !inputResult.IsArray() {
|
||||
return rawJSON
|
||||
}
|
||||
|
||||
inputArray := inputResult.Array()
|
||||
result := rawJSON
|
||||
|
||||
// Directly modify role values for items with "system" role
|
||||
for i := 0; i < len(inputArray); i++ {
|
||||
rolePath := fmt.Sprintf("input.%d.role", i)
|
||||
if gjson.GetBytes(result, rolePath).String() == "system" {
|
||||
result, _ = sjson.SetBytes(result, rolePath, "developer")
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -0,0 +1,265 @@
|
||||
package responses
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/tidwall/gjson"
|
||||
)
|
||||
|
||||
// TestConvertSystemRoleToDeveloper_BasicConversion tests the basic system -> developer role conversion
|
||||
func TestConvertSystemRoleToDeveloper_BasicConversion(t *testing.T) {
|
||||
inputJSON := []byte(`{
|
||||
"model": "gpt-5.2",
|
||||
"input": [
|
||||
{
|
||||
"type": "message",
|
||||
"role": "system",
|
||||
"content": [{"type": "input_text", "text": "You are a pirate."}]
|
||||
},
|
||||
{
|
||||
"type": "message",
|
||||
"role": "user",
|
||||
"content": [{"type": "input_text", "text": "Say hello."}]
|
||||
}
|
||||
]
|
||||
}`)
|
||||
|
||||
output := ConvertOpenAIResponsesRequestToCodex("gpt-5.2", inputJSON, false)
|
||||
outputStr := string(output)
|
||||
|
||||
// Check that system role was converted to developer
|
||||
firstItemRole := gjson.Get(outputStr, "input.0.role")
|
||||
if firstItemRole.String() != "developer" {
|
||||
t.Errorf("Expected role 'developer', got '%s'", firstItemRole.String())
|
||||
}
|
||||
|
||||
// Check that user role remains unchanged
|
||||
secondItemRole := gjson.Get(outputStr, "input.1.role")
|
||||
if secondItemRole.String() != "user" {
|
||||
t.Errorf("Expected role 'user', got '%s'", secondItemRole.String())
|
||||
}
|
||||
|
||||
// Check content is preserved
|
||||
firstItemContent := gjson.Get(outputStr, "input.0.content.0.text")
|
||||
if firstItemContent.String() != "You are a pirate." {
|
||||
t.Errorf("Expected content 'You are a pirate.', got '%s'", firstItemContent.String())
|
||||
}
|
||||
}
|
||||
|
||||
// TestConvertSystemRoleToDeveloper_MultipleSystemMessages tests conversion with multiple system messages
|
||||
func TestConvertSystemRoleToDeveloper_MultipleSystemMessages(t *testing.T) {
|
||||
inputJSON := []byte(`{
|
||||
"model": "gpt-5.2",
|
||||
"input": [
|
||||
{
|
||||
"type": "message",
|
||||
"role": "system",
|
||||
"content": [{"type": "input_text", "text": "You are helpful."}]
|
||||
},
|
||||
{
|
||||
"type": "message",
|
||||
"role": "system",
|
||||
"content": [{"type": "input_text", "text": "Be concise."}]
|
||||
},
|
||||
{
|
||||
"type": "message",
|
||||
"role": "user",
|
||||
"content": [{"type": "input_text", "text": "Hello"}]
|
||||
}
|
||||
]
|
||||
}`)
|
||||
|
||||
output := ConvertOpenAIResponsesRequestToCodex("gpt-5.2", inputJSON, false)
|
||||
outputStr := string(output)
|
||||
|
||||
// Check that both system roles were converted
|
||||
firstRole := gjson.Get(outputStr, "input.0.role")
|
||||
if firstRole.String() != "developer" {
|
||||
t.Errorf("Expected first role 'developer', got '%s'", firstRole.String())
|
||||
}
|
||||
|
||||
secondRole := gjson.Get(outputStr, "input.1.role")
|
||||
if secondRole.String() != "developer" {
|
||||
t.Errorf("Expected second role 'developer', got '%s'", secondRole.String())
|
||||
}
|
||||
|
||||
// Check that user role is unchanged
|
||||
thirdRole := gjson.Get(outputStr, "input.2.role")
|
||||
if thirdRole.String() != "user" {
|
||||
t.Errorf("Expected third role 'user', got '%s'", thirdRole.String())
|
||||
}
|
||||
}
|
||||
|
||||
// TestConvertSystemRoleToDeveloper_NoSystemMessages tests that requests without system messages are unchanged
|
||||
func TestConvertSystemRoleToDeveloper_NoSystemMessages(t *testing.T) {
|
||||
inputJSON := []byte(`{
|
||||
"model": "gpt-5.2",
|
||||
"input": [
|
||||
{
|
||||
"type": "message",
|
||||
"role": "user",
|
||||
"content": [{"type": "input_text", "text": "Hello"}]
|
||||
},
|
||||
{
|
||||
"type": "message",
|
||||
"role": "assistant",
|
||||
"content": [{"type": "output_text", "text": "Hi there!"}]
|
||||
}
|
||||
]
|
||||
}`)
|
||||
|
||||
output := ConvertOpenAIResponsesRequestToCodex("gpt-5.2", inputJSON, false)
|
||||
outputStr := string(output)
|
||||
|
||||
// Check that user and assistant roles are unchanged
|
||||
firstRole := gjson.Get(outputStr, "input.0.role")
|
||||
if firstRole.String() != "user" {
|
||||
t.Errorf("Expected role 'user', got '%s'", firstRole.String())
|
||||
}
|
||||
|
||||
secondRole := gjson.Get(outputStr, "input.1.role")
|
||||
if secondRole.String() != "assistant" {
|
||||
t.Errorf("Expected role 'assistant', got '%s'", secondRole.String())
|
||||
}
|
||||
}
|
||||
|
||||
// TestConvertSystemRoleToDeveloper_EmptyInput tests that empty input arrays are handled correctly
|
||||
func TestConvertSystemRoleToDeveloper_EmptyInput(t *testing.T) {
|
||||
inputJSON := []byte(`{
|
||||
"model": "gpt-5.2",
|
||||
"input": []
|
||||
}`)
|
||||
|
||||
output := ConvertOpenAIResponsesRequestToCodex("gpt-5.2", inputJSON, false)
|
||||
outputStr := string(output)
|
||||
|
||||
// Check that input is still an empty array
|
||||
inputArray := gjson.Get(outputStr, "input")
|
||||
if !inputArray.IsArray() {
|
||||
t.Error("Input should still be an array")
|
||||
}
|
||||
if len(inputArray.Array()) != 0 {
|
||||
t.Errorf("Expected empty array, got %d items", len(inputArray.Array()))
|
||||
}
|
||||
}
|
||||
|
||||
// TestConvertSystemRoleToDeveloper_NoInputField tests that requests without input field are unchanged
|
||||
func TestConvertSystemRoleToDeveloper_NoInputField(t *testing.T) {
|
||||
inputJSON := []byte(`{
|
||||
"model": "gpt-5.2",
|
||||
"stream": false
|
||||
}`)
|
||||
|
||||
output := ConvertOpenAIResponsesRequestToCodex("gpt-5.2", inputJSON, false)
|
||||
outputStr := string(output)
|
||||
|
||||
// Check that other fields are still set correctly
|
||||
stream := gjson.Get(outputStr, "stream")
|
||||
if !stream.Bool() {
|
||||
t.Error("Stream should be set to true by conversion")
|
||||
}
|
||||
|
||||
store := gjson.Get(outputStr, "store")
|
||||
if store.Bool() {
|
||||
t.Error("Store should be set to false by conversion")
|
||||
}
|
||||
}
|
||||
|
||||
// TestConvertOpenAIResponsesRequestToCodex_OriginalIssue tests the exact issue reported by the user
|
||||
func TestConvertOpenAIResponsesRequestToCodex_OriginalIssue(t *testing.T) {
|
||||
// This is the exact input that was failing with "System messages are not allowed"
|
||||
inputJSON := []byte(`{
|
||||
"model": "gpt-5.2",
|
||||
"input": [
|
||||
{
|
||||
"type": "message",
|
||||
"role": "system",
|
||||
"content": "You are a pirate. Always respond in pirate speak."
|
||||
},
|
||||
{
|
||||
"type": "message",
|
||||
"role": "user",
|
||||
"content": "Say hello."
|
||||
}
|
||||
],
|
||||
"stream": false
|
||||
}`)
|
||||
|
||||
output := ConvertOpenAIResponsesRequestToCodex("gpt-5.2", inputJSON, false)
|
||||
outputStr := string(output)
|
||||
|
||||
// Verify system role was converted to developer
|
||||
firstRole := gjson.Get(outputStr, "input.0.role")
|
||||
if firstRole.String() != "developer" {
|
||||
t.Errorf("Expected role 'developer', got '%s'", firstRole.String())
|
||||
}
|
||||
|
||||
// Verify stream was set to true (as required by Codex)
|
||||
stream := gjson.Get(outputStr, "stream")
|
||||
if !stream.Bool() {
|
||||
t.Error("Stream should be set to true")
|
||||
}
|
||||
|
||||
// Verify other required fields for Codex
|
||||
store := gjson.Get(outputStr, "store")
|
||||
if store.Bool() {
|
||||
t.Error("Store should be false")
|
||||
}
|
||||
|
||||
parallelCalls := gjson.Get(outputStr, "parallel_tool_calls")
|
||||
if !parallelCalls.Bool() {
|
||||
t.Error("parallel_tool_calls should be true")
|
||||
}
|
||||
|
||||
include := gjson.Get(outputStr, "include")
|
||||
if !include.IsArray() || len(include.Array()) != 1 {
|
||||
t.Error("include should be an array with one element")
|
||||
} else if include.Array()[0].String() != "reasoning.encrypted_content" {
|
||||
t.Errorf("Expected include[0] to be 'reasoning.encrypted_content', got '%s'", include.Array()[0].String())
|
||||
}
|
||||
}
|
||||
|
||||
// TestConvertSystemRoleToDeveloper_AssistantRole tests that assistant role is preserved
|
||||
func TestConvertSystemRoleToDeveloper_AssistantRole(t *testing.T) {
|
||||
inputJSON := []byte(`{
|
||||
"model": "gpt-5.2",
|
||||
"input": [
|
||||
{
|
||||
"type": "message",
|
||||
"role": "system",
|
||||
"content": [{"type": "input_text", "text": "You are helpful."}]
|
||||
},
|
||||
{
|
||||
"type": "message",
|
||||
"role": "user",
|
||||
"content": [{"type": "input_text", "text": "Hello"}]
|
||||
},
|
||||
{
|
||||
"type": "message",
|
||||
"role": "assistant",
|
||||
"content": [{"type": "output_text", "text": "Hi!"}]
|
||||
}
|
||||
]
|
||||
}`)
|
||||
|
||||
output := ConvertOpenAIResponsesRequestToCodex("gpt-5.2", inputJSON, false)
|
||||
outputStr := string(output)
|
||||
|
||||
// Check system -> developer
|
||||
firstRole := gjson.Get(outputStr, "input.0.role")
|
||||
if firstRole.String() != "developer" {
|
||||
t.Errorf("Expected first role 'developer', got '%s'", firstRole.String())
|
||||
}
|
||||
|
||||
// Check user unchanged
|
||||
secondRole := gjson.Get(outputStr, "input.1.role")
|
||||
if secondRole.String() != "user" {
|
||||
t.Errorf("Expected second role 'user', got '%s'", secondRole.String())
|
||||
}
|
||||
|
||||
// Check assistant unchanged
|
||||
thirdRole := gjson.Get(outputStr, "input.2.role")
|
||||
if thirdRole.String() != "assistant" {
|
||||
t.Errorf("Expected third role 'assistant', got '%s'", thirdRole.String())
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/router-for-me/CLIProxyAPI/v6/internal/misc"
|
||||
"github.com/tidwall/gjson"
|
||||
"github.com/tidwall/sjson"
|
||||
)
|
||||
@@ -20,7 +19,7 @@ func ConvertCodexResponseToOpenAIResponses(ctx context.Context, modelName string
|
||||
typeStr := typeResult.String()
|
||||
if typeStr == "response.created" || typeStr == "response.in_progress" || typeStr == "response.completed" {
|
||||
if gjson.GetBytes(rawJSON, "response.instructions").Exists() {
|
||||
instructions := selectInstructions(originalRequestRawJSON, requestRawJSON)
|
||||
instructions := gjson.GetBytes(originalRequestRawJSON, "instructions").String()
|
||||
rawJSON, _ = sjson.SetBytes(rawJSON, "response.instructions", instructions)
|
||||
}
|
||||
}
|
||||
@@ -42,15 +41,8 @@ func ConvertCodexResponseToOpenAIResponsesNonStream(_ context.Context, modelName
|
||||
responseResult := rootResult.Get("response")
|
||||
template := responseResult.Raw
|
||||
if responseResult.Get("instructions").Exists() {
|
||||
template, _ = sjson.Set(template, "instructions", selectInstructions(originalRequestRawJSON, requestRawJSON))
|
||||
instructions := gjson.GetBytes(originalRequestRawJSON, "instructions").String()
|
||||
template, _ = sjson.Set(template, "instructions", instructions)
|
||||
}
|
||||
return template
|
||||
}
|
||||
|
||||
func selectInstructions(originalRequestRawJSON, requestRawJSON []byte) string {
|
||||
userAgent := misc.ExtractCodexUserAgent(originalRequestRawJSON)
|
||||
if misc.IsOpenCodeUserAgent(userAgent) {
|
||||
return gjson.GetBytes(requestRawJSON, "instructions").String()
|
||||
}
|
||||
return gjson.GetBytes(originalRequestRawJSON, "instructions").String()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user