Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .ccs-fork-upstream.env
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
UPSTREAM_TAG=v7.2.105
UPSTREAM_COMMIT=4a2eb54dc6bf943196be4fb515e6a9407a4db143
UPSTREAM_TAG=v7.2.109
UPSTREAM_COMMIT=928478e4b91533cec05a763bfac3edad9c3e76cf
37 changes: 37 additions & 0 deletions internal/api/handlers/management/auth_files.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/gin-gonic/gin"
"github.com/router-for-me/CLIProxyAPI/v7/internal/auth/codex"
"github.com/router-for-me/CLIProxyAPI/v7/internal/config"
"github.com/router-for-me/CLIProxyAPI/v7/internal/credentialweight"
"github.com/router-for-me/CLIProxyAPI/v7/internal/registry"
coreauth "github.com/router-for-me/CLIProxyAPI/v7/sdk/cliproxy/auth"
log "github.com/sirupsen/logrus"
Expand Down Expand Up @@ -260,6 +261,20 @@ func (h *Handler) listAuthFilesFromDisk(c *gin.Context) {
}
}
}
if wv := gjson.GetBytes(data, coreauth.AttributeWeight); wv.Exists() {
var rawWeight string
switch wv.Type {
case gjson.Number:
rawWeight = wv.Raw
case gjson.String:
rawWeight = wv.String()
}
if rawWeight != "" {
if weight, errWeight := credentialweight.ParseString(rawWeight); errWeight == nil {
fileData[coreauth.AttributeWeight] = weight
}
}
}
if nv := gjson.GetBytes(data, "note"); nv.Exists() && nv.Type == gjson.String {
if trimmed := strings.TrimSpace(nv.String()); trimmed != "" {
fileData["note"] = trimmed
Expand Down Expand Up @@ -403,12 +418,34 @@ func (h *Handler) buildAuthFileEntryLocked(auth *coreauth.Auth) gin.H {
}
}
}
if weight, ok := authWeightValue(auth); ok {
entry[coreauth.AttributeWeight] = weight
}
if websockets, ok := authWebsocketsValue(auth); ok {
entry["websockets"] = websockets
}
return entry
}

func authWeightValue(auth *coreauth.Auth) (int64, bool) {
if auth == nil {
return 0, false
}
if rawWeight := strings.TrimSpace(authAttribute(auth, coreauth.AttributeWeight)); rawWeight != "" {
weight, errWeight := credentialweight.ParseString(rawWeight)
return weight, errWeight == nil
}
if auth.Metadata == nil {
return 0, false
}
rawWeight, ok := auth.Metadata[coreauth.AttributeWeight]
if !ok || rawWeight == nil {
return 0, false
}
weight, errWeight := credentialweight.ParseValue(rawWeight)
return weight, errWeight == nil
}

func authWebsocketsValue(auth *coreauth.Auth) (bool, bool) {
if auth == nil {
return false, false
Expand Down
52 changes: 46 additions & 6 deletions internal/runtime/executor/antigravity_schema_sanitize_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,47 @@ func TestSanitizeAntigravityRequestSchemasKeepsResponseSchemasPlaceholderFree(t
}
}

func TestAntigravityBuildRequestKeepsJSONObjectSchemaPlaceholderFree(t *testing.T) {
func TestSanitizeAntigravityRequestSchemasPreservesResponseUnionAndEnumType(t *testing.T) {
payload := `{"request":{
"tools":[{"functionDeclarations":[{"name":"tool","parameters":{"type":"object","properties":{
"choice":{"anyOf":[{"type":"string"},{"type":"null"}]},
"level":{"type":"number","enum":[1,2]}
}}}]}],
"generationConfig":{"responseSchema":{"type":"object","properties":{
"action":{"anyOf":[
{"type":"object","properties":{"name":{"type":"string"}},"required":["name"]},
{"type":"null"}
]},
"conviction":{"type":"number","enum":[0.25,0.5,1]}
}}}
}}`

got := sanitizeAntigravityRequestSchemas(payload, true)
responseSchema := gjson.Get(got, "request.generationConfig.responseSchema")
union := responseSchema.Get("properties.action.anyOf")
if !union.IsArray() || len(union.Array()) != 2 || union.Get("1.type").String() != "null" {
t.Errorf("response anyOf union was flattened: %s", responseSchema.Raw)
}
conviction := responseSchema.Get("properties.conviction")
if gotType := conviction.Get("type").String(); gotType != "number" {
t.Errorf("response enum type = %q, want number: %s", gotType, responseSchema.Raw)
}
for _, enumValue := range conviction.Get("enum").Array() {
if enumValue.Type != gjson.String {
t.Errorf("response enum value is not a string: %s", conviction.Raw)
}
}

toolSchema := gjson.Get(got, "request.tools.0.functionDeclarations.0.parameters")
if toolSchema.Get("properties.choice.anyOf").Exists() {
t.Errorf("tool anyOf union was not flattened: %s", toolSchema.Raw)
}
if gotType := toolSchema.Get("properties.level.type").String(); gotType != "string" {
t.Errorf("tool enum type = %q, want string: %s", gotType, toolSchema.Raw)
}
}

func TestAntigravityBuildRequestKeepsJSONObjectMimeOnly(t *testing.T) {
input := []byte(`{"model":"gemini-3.1-pro-low","messages":[{"role":"user","content":"hi"}],"response_format":{"type":"json_object"}}`)
translated := antigravitychat.ConvertOpenAIRequestToAntigravity("gemini-3.1-pro-low", input, false)
body := buildRequestBodyFromRawPayload(t, "gemini-3.1-pro-low", translated)
Expand All @@ -283,12 +323,12 @@ func TestAntigravityBuildRequestKeepsJSONObjectSchemaPlaceholderFree(t *testing.
t.Fatal(errMarshal)
}

schema := gjson.GetBytes(encoded, "request.generationConfig.responseSchema")
if got := schema.Get("type").String(); got != "object" {
t.Fatalf("responseSchema.type = %q, want object: %s", got, encoded)
generationConfig := gjson.GetBytes(encoded, "request.generationConfig")
if got := generationConfig.Get("responseMimeType").String(); got != "application/json" {
t.Fatalf("responseMimeType = %q, want application/json: %s", got, encoded)
}
if schema.Get("properties.reason").Exists() || schema.Get("required").Exists() {
t.Fatalf("json_object schema gained tool placeholders: %s", schema.Raw)
if generationConfig.Get("responseSchema").Exists() {
t.Fatalf("responseSchema should not be set for json_object: %s", encoded)
}
}

Expand Down
Loading