mirror of
https://github.com/router-for-me/CLIProxyAPIPlus.git
synced 2026-04-25 04:56:10 +00:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
93d7883513 | ||
|
|
015a3e8a83 | ||
|
|
bc7167e9fe | ||
|
|
384578a88c | ||
|
|
6b074653f2 | ||
|
|
65b4e1ec6c |
@@ -517,8 +517,8 @@ func (e *AntigravityExecutor) convertStreamToNonStream(stream []byte) []byte {
|
|||||||
}
|
}
|
||||||
if usageResult := responseNode.Get("usageMetadata"); usageResult.Exists() {
|
if usageResult := responseNode.Get("usageMetadata"); usageResult.Exists() {
|
||||||
usageRaw = usageResult.Raw
|
usageRaw = usageResult.Raw
|
||||||
} else if usageResult := root.Get("usageMetadata"); usageResult.Exists() {
|
} else if usageMetadataResult := root.Get("usageMetadata"); usageMetadataResult.Exists() {
|
||||||
usageRaw = usageResult.Raw
|
usageRaw = usageMetadataResult.Raw
|
||||||
}
|
}
|
||||||
|
|
||||||
if partsResult := responseNode.Get("candidates.0.content.parts"); partsResult.IsArray() {
|
if partsResult := responseNode.Get("candidates.0.content.parts"); partsResult.IsArray() {
|
||||||
@@ -642,7 +642,6 @@ func (e *AntigravityExecutor) ExecuteStream(ctx context.Context, auth *cliproxya
|
|||||||
err = errReq
|
err = errReq
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
httpResp, errDo := httpClient.Do(httpReq)
|
httpResp, errDo := httpClient.Do(httpReq)
|
||||||
if errDo != nil {
|
if errDo != nil {
|
||||||
recordAPIResponseError(ctx, e.cfg, errDo)
|
recordAPIResponseError(ctx, e.cfg, errDo)
|
||||||
@@ -1004,10 +1003,10 @@ func FetchAntigravityModels(ctx context.Context, auth *cliproxyauth.Auth, cfg *c
|
|||||||
case "chat_20706", "chat_23310", "gemini-2.5-flash-thinking", "gemini-3-pro-low", "gemini-2.5-pro":
|
case "chat_20706", "chat_23310", "gemini-2.5-flash-thinking", "gemini-3-pro-low", "gemini-2.5-pro":
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
cfg := modelConfig[modelID]
|
modelCfg := modelConfig[modelID]
|
||||||
modelName := modelID
|
modelName := modelID
|
||||||
if cfg != nil && cfg.Name != "" {
|
if modelCfg != nil && modelCfg.Name != "" {
|
||||||
modelName = cfg.Name
|
modelName = modelCfg.Name
|
||||||
}
|
}
|
||||||
modelInfo := ®istry.ModelInfo{
|
modelInfo := ®istry.ModelInfo{
|
||||||
ID: modelID,
|
ID: modelID,
|
||||||
@@ -1021,12 +1020,12 @@ func FetchAntigravityModels(ctx context.Context, auth *cliproxyauth.Auth, cfg *c
|
|||||||
Type: antigravityAuthType,
|
Type: antigravityAuthType,
|
||||||
}
|
}
|
||||||
// Look up Thinking support from static config using upstream model name.
|
// Look up Thinking support from static config using upstream model name.
|
||||||
if cfg != nil {
|
if modelCfg != nil {
|
||||||
if cfg.Thinking != nil {
|
if modelCfg.Thinking != nil {
|
||||||
modelInfo.Thinking = cfg.Thinking
|
modelInfo.Thinking = modelCfg.Thinking
|
||||||
}
|
}
|
||||||
if cfg.MaxCompletionTokens > 0 {
|
if modelCfg.MaxCompletionTokens > 0 {
|
||||||
modelInfo.MaxCompletionTokens = cfg.MaxCompletionTokens
|
modelInfo.MaxCompletionTokens = modelCfg.MaxCompletionTokens
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
models = append(models, modelInfo)
|
models = append(models, modelInfo)
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ func applyPayloadConfigWithRoot(cfg *config.Config, model, protocol, root string
|
|||||||
if model == "" {
|
if model == "" {
|
||||||
return payload
|
return payload
|
||||||
}
|
}
|
||||||
|
candidates := payloadModelCandidates(cfg, model, protocol)
|
||||||
out := payload
|
out := payload
|
||||||
source := original
|
source := original
|
||||||
if len(source) == 0 {
|
if len(source) == 0 {
|
||||||
@@ -34,7 +35,7 @@ func applyPayloadConfigWithRoot(cfg *config.Config, model, protocol, root string
|
|||||||
// Apply default rules: first write wins per field across all matching rules.
|
// Apply default rules: first write wins per field across all matching rules.
|
||||||
for i := range rules.Default {
|
for i := range rules.Default {
|
||||||
rule := &rules.Default[i]
|
rule := &rules.Default[i]
|
||||||
if !payloadRuleMatchesModel(rule, model, protocol) {
|
if !payloadRuleMatchesModels(rule, protocol, candidates) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for path, value := range rule.Params {
|
for path, value := range rule.Params {
|
||||||
@@ -59,7 +60,7 @@ func applyPayloadConfigWithRoot(cfg *config.Config, model, protocol, root string
|
|||||||
// Apply default raw rules: first write wins per field across all matching rules.
|
// Apply default raw rules: first write wins per field across all matching rules.
|
||||||
for i := range rules.DefaultRaw {
|
for i := range rules.DefaultRaw {
|
||||||
rule := &rules.DefaultRaw[i]
|
rule := &rules.DefaultRaw[i]
|
||||||
if !payloadRuleMatchesModel(rule, model, protocol) {
|
if !payloadRuleMatchesModels(rule, protocol, candidates) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for path, value := range rule.Params {
|
for path, value := range rule.Params {
|
||||||
@@ -88,7 +89,7 @@ func applyPayloadConfigWithRoot(cfg *config.Config, model, protocol, root string
|
|||||||
// Apply override rules: last write wins per field across all matching rules.
|
// Apply override rules: last write wins per field across all matching rules.
|
||||||
for i := range rules.Override {
|
for i := range rules.Override {
|
||||||
rule := &rules.Override[i]
|
rule := &rules.Override[i]
|
||||||
if !payloadRuleMatchesModel(rule, model, protocol) {
|
if !payloadRuleMatchesModels(rule, protocol, candidates) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for path, value := range rule.Params {
|
for path, value := range rule.Params {
|
||||||
@@ -106,7 +107,7 @@ func applyPayloadConfigWithRoot(cfg *config.Config, model, protocol, root string
|
|||||||
// Apply override raw rules: last write wins per field across all matching rules.
|
// Apply override raw rules: last write wins per field across all matching rules.
|
||||||
for i := range rules.OverrideRaw {
|
for i := range rules.OverrideRaw {
|
||||||
rule := &rules.OverrideRaw[i]
|
rule := &rules.OverrideRaw[i]
|
||||||
if !payloadRuleMatchesModel(rule, model, protocol) {
|
if !payloadRuleMatchesModels(rule, protocol, candidates) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for path, value := range rule.Params {
|
for path, value := range rule.Params {
|
||||||
@@ -128,6 +129,18 @@ func applyPayloadConfigWithRoot(cfg *config.Config, model, protocol, root string
|
|||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func payloadRuleMatchesModels(rule *config.PayloadRule, protocol string, models []string) bool {
|
||||||
|
if rule == nil || len(models) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, model := range models {
|
||||||
|
if payloadRuleMatchesModel(rule, model, protocol) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func payloadRuleMatchesModel(rule *config.PayloadRule, model, protocol string) bool {
|
func payloadRuleMatchesModel(rule *config.PayloadRule, model, protocol string) bool {
|
||||||
if rule == nil {
|
if rule == nil {
|
||||||
return false
|
return false
|
||||||
@@ -150,6 +163,65 @@ func payloadRuleMatchesModel(rule *config.PayloadRule, model, protocol string) b
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func payloadModelCandidates(cfg *config.Config, model, protocol string) []string {
|
||||||
|
model = strings.TrimSpace(model)
|
||||||
|
if model == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
candidates := []string{model}
|
||||||
|
if cfg == nil {
|
||||||
|
return candidates
|
||||||
|
}
|
||||||
|
aliases := payloadModelAliases(cfg, model, protocol)
|
||||||
|
if len(aliases) == 0 {
|
||||||
|
return candidates
|
||||||
|
}
|
||||||
|
seen := map[string]struct{}{strings.ToLower(model): struct{}{}}
|
||||||
|
for _, alias := range aliases {
|
||||||
|
alias = strings.TrimSpace(alias)
|
||||||
|
if alias == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
key := strings.ToLower(alias)
|
||||||
|
if _, ok := seen[key]; ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
seen[key] = struct{}{}
|
||||||
|
candidates = append(candidates, alias)
|
||||||
|
}
|
||||||
|
return candidates
|
||||||
|
}
|
||||||
|
|
||||||
|
func payloadModelAliases(cfg *config.Config, model, protocol string) []string {
|
||||||
|
if cfg == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
model = strings.TrimSpace(model)
|
||||||
|
if model == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
channel := strings.ToLower(strings.TrimSpace(protocol))
|
||||||
|
if channel == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
entries := cfg.OAuthModelAlias[channel]
|
||||||
|
if len(entries) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
aliases := make([]string, 0, 2)
|
||||||
|
for _, entry := range entries {
|
||||||
|
if !strings.EqualFold(strings.TrimSpace(entry.Name), model) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
alias := strings.TrimSpace(entry.Alias)
|
||||||
|
if alias == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
aliases = append(aliases, alias)
|
||||||
|
}
|
||||||
|
return aliases
|
||||||
|
}
|
||||||
|
|
||||||
// buildPayloadPath combines an optional root path with a relative parameter path.
|
// buildPayloadPath combines an optional root path with a relative parameter path.
|
||||||
// When root is empty, the parameter path is used as-is. When root is non-empty,
|
// When root is empty, the parameter path is used as-is. When root is non-empty,
|
||||||
// the parameter path is treated as relative to root.
|
// the parameter path is treated as relative to root.
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ func ConvertClaudeRequestToCodex(modelName string, inputRawJSON []byte, _ bool)
|
|||||||
systemsResult := rootResult.Get("system")
|
systemsResult := rootResult.Get("system")
|
||||||
if systemsResult.IsArray() {
|
if systemsResult.IsArray() {
|
||||||
systemResults := systemsResult.Array()
|
systemResults := systemsResult.Array()
|
||||||
message := `{"type":"message","role":"user","content":[]}`
|
message := `{"type":"message","role":"developer","content":[]}`
|
||||||
for i := 0; i < len(systemResults); i++ {
|
for i := 0; i < len(systemResults); i++ {
|
||||||
systemResult := systemResults[i]
|
systemResult := systemResults[i]
|
||||||
systemTypeResult := systemResult.Get("type")
|
systemTypeResult := systemResult.Get("type")
|
||||||
@@ -245,21 +245,23 @@ func ConvertClaudeRequestToCodex(modelName string, inputRawJSON []byte, _ bool)
|
|||||||
template, _ = sjson.Set(template, "include", []string{"reasoning.encrypted_content"})
|
template, _ = sjson.Set(template, "include", []string{"reasoning.encrypted_content"})
|
||||||
|
|
||||||
// Add a first message to ignore system instructions and ensure proper execution.
|
// Add a first message to ignore system instructions and ensure proper execution.
|
||||||
inputResult := gjson.Get(template, "input")
|
if misc.GetCodexInstructionsEnabled() {
|
||||||
if inputResult.Exists() && inputResult.IsArray() {
|
inputResult := gjson.Get(template, "input")
|
||||||
inputResults := inputResult.Array()
|
if inputResult.Exists() && inputResult.IsArray() {
|
||||||
newInput := "[]"
|
inputResults := inputResult.Array()
|
||||||
for i := 0; i < len(inputResults); i++ {
|
newInput := "[]"
|
||||||
if i == 0 {
|
for i := 0; i < len(inputResults); i++ {
|
||||||
firstText := inputResults[i].Get("content.0.text")
|
if i == 0 {
|
||||||
firstInstructions := "EXECUTE ACCORDING TO THE FOLLOWING INSTRUCTIONS!!!"
|
firstText := inputResults[i].Get("content.0.text")
|
||||||
if firstText.Exists() && firstText.String() != firstInstructions {
|
firstInstructions := "EXECUTE ACCORDING TO THE FOLLOWING INSTRUCTIONS!!!"
|
||||||
newInput, _ = sjson.SetRaw(newInput, "-1", `{"type":"message","role":"user","content":[{"type":"input_text","text":"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)
|
||||||
}
|
}
|
||||||
newInput, _ = sjson.SetRaw(newInput, "-1", inputResults[i].Raw)
|
template, _ = sjson.SetRaw(template, "input", newInput)
|
||||||
}
|
}
|
||||||
template, _ = sjson.SetRaw(template, "input", newInput)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return []byte(template)
|
return []byte(template)
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ func ConvertGeminiRequestToCodex(modelName string, inputRawJSON []byte, _ bool)
|
|||||||
// System instruction -> as a user message with input_text parts
|
// System instruction -> as a user message with input_text parts
|
||||||
sysParts := root.Get("system_instruction.parts")
|
sysParts := root.Get("system_instruction.parts")
|
||||||
if sysParts.IsArray() {
|
if sysParts.IsArray() {
|
||||||
msg := `{"type":"message","role":"user","content":[]}`
|
msg := `{"type":"message","role":"developer","content":[]}`
|
||||||
arr := sysParts.Array()
|
arr := sysParts.Array()
|
||||||
for i := 0; i < len(arr); i++ {
|
for i := 0; i < len(arr); i++ {
|
||||||
p := arr[i]
|
p := arr[i]
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ func ConvertOpenAIRequestToCodex(modelName string, inputRawJSON []byte, stream b
|
|||||||
rawJSON := bytes.Clone(inputRawJSON)
|
rawJSON := bytes.Clone(inputRawJSON)
|
||||||
userAgent := misc.ExtractCodexUserAgent(rawJSON)
|
userAgent := misc.ExtractCodexUserAgent(rawJSON)
|
||||||
// Start with empty JSON object
|
// Start with empty JSON object
|
||||||
out := `{}`
|
out := `{"instructions":""}`
|
||||||
|
|
||||||
// Stream must be set to true
|
// Stream must be set to true
|
||||||
out, _ = sjson.Set(out, "stream", stream)
|
out, _ = sjson.Set(out, "stream", stream)
|
||||||
@@ -98,7 +98,9 @@ func ConvertOpenAIRequestToCodex(modelName string, inputRawJSON []byte, stream b
|
|||||||
// Extract system instructions from first system message (string or text object)
|
// Extract system instructions from first system message (string or text object)
|
||||||
messages := gjson.GetBytes(rawJSON, "messages")
|
messages := gjson.GetBytes(rawJSON, "messages")
|
||||||
_, instructions := misc.CodexInstructionsForModel(modelName, "", userAgent)
|
_, instructions := misc.CodexInstructionsForModel(modelName, "", userAgent)
|
||||||
out, _ = sjson.Set(out, "instructions", instructions)
|
if misc.GetCodexInstructionsEnabled() {
|
||||||
|
out, _ = sjson.Set(out, "instructions", instructions)
|
||||||
|
}
|
||||||
// if messages.IsArray() {
|
// if messages.IsArray() {
|
||||||
// arr := messages.Array()
|
// arr := messages.Array()
|
||||||
// for i := 0; i < len(arr); i++ {
|
// for i := 0; i < len(arr); i++ {
|
||||||
@@ -141,7 +143,7 @@ func ConvertOpenAIRequestToCodex(modelName string, inputRawJSON []byte, stream b
|
|||||||
msg := `{}`
|
msg := `{}`
|
||||||
msg, _ = sjson.Set(msg, "type", "message")
|
msg, _ = sjson.Set(msg, "type", "message")
|
||||||
if role == "system" {
|
if role == "system" {
|
||||||
msg, _ = sjson.Set(msg, "role", "user")
|
msg, _ = sjson.Set(msg, "role", "developer")
|
||||||
} else {
|
} else {
|
||||||
msg, _ = sjson.Set(msg, "role", role)
|
msg, _ = sjson.Set(msg, "role", role)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -240,9 +240,13 @@ func BuildKiroPayload(claudeBody []byte, modelID, profileArn, origin string, isA
|
|||||||
// Process messages and build history
|
// Process messages and build history
|
||||||
history, currentUserMsg, currentToolResults := processMessages(messages, modelID, origin)
|
history, currentUserMsg, currentToolResults := processMessages(messages, modelID, origin)
|
||||||
|
|
||||||
// Build content with system prompt
|
// Build content with system prompt (only on first turn to avoid re-injection)
|
||||||
if currentUserMsg != nil {
|
if currentUserMsg != nil {
|
||||||
currentUserMsg.Content = buildFinalContent(currentUserMsg.Content, systemPrompt, currentToolResults)
|
effectiveSystemPrompt := systemPrompt
|
||||||
|
if len(history) > 0 {
|
||||||
|
effectiveSystemPrompt = "" // Don't re-inject on subsequent turns
|
||||||
|
}
|
||||||
|
currentUserMsg.Content = buildFinalContent(currentUserMsg.Content, effectiveSystemPrompt, currentToolResults)
|
||||||
|
|
||||||
// Deduplicate currentToolResults
|
// Deduplicate currentToolResults
|
||||||
currentToolResults = deduplicateToolResults(currentToolResults)
|
currentToolResults = deduplicateToolResults(currentToolResults)
|
||||||
|
|||||||
@@ -56,8 +56,12 @@ func (h *GeminiAPIHandler) GeminiModels(c *gin.Context) {
|
|||||||
for k, v := range model {
|
for k, v := range model {
|
||||||
normalizedModel[k] = v
|
normalizedModel[k] = v
|
||||||
}
|
}
|
||||||
if name, ok := normalizedModel["name"].(string); ok && name != "" && !strings.HasPrefix(name, "models/") {
|
if name, ok := normalizedModel["name"].(string); ok && name != "" {
|
||||||
normalizedModel["name"] = "models/" + name
|
if !strings.HasPrefix(name, "models/") {
|
||||||
|
normalizedModel["name"] = "models/" + name
|
||||||
|
}
|
||||||
|
normalizedModel["displayName"] = name
|
||||||
|
normalizedModel["description"] = name
|
||||||
}
|
}
|
||||||
if _, ok := normalizedModel["supportedGenerationMethods"]; !ok {
|
if _, ok := normalizedModel["supportedGenerationMethods"]; !ok {
|
||||||
normalizedModel["supportedGenerationMethods"] = defaultMethods
|
normalizedModel["supportedGenerationMethods"] = defaultMethods
|
||||||
|
|||||||
@@ -1222,6 +1222,9 @@ func rewriteModelInfoName(name, oldID, newID string) string {
|
|||||||
if strings.EqualFold(oldID, newID) {
|
if strings.EqualFold(oldID, newID) {
|
||||||
return name
|
return name
|
||||||
}
|
}
|
||||||
|
if strings.EqualFold(trimmed, oldID) {
|
||||||
|
return newID
|
||||||
|
}
|
||||||
if strings.HasSuffix(trimmed, "/"+oldID) {
|
if strings.HasSuffix(trimmed, "/"+oldID) {
|
||||||
prefix := strings.TrimSuffix(trimmed, oldID)
|
prefix := strings.TrimSuffix(trimmed, oldID)
|
||||||
return prefix + newID
|
return prefix + newID
|
||||||
|
|||||||
Reference in New Issue
Block a user