mirror of
https://github.com/router-for-me/CLIProxyAPI.git
synced 2026-06-23 23:54:09 +08:00
- Deleted `geminicli` provider and related `Apply` logic. - Removed all translator packages specific to Gemini CLI (Claude, Codex integrations). - Purged associated test files for Gemini CLI translation. - Removed `GeminiAuthenticator` and all associated authentication logic (OAuth flows, token handling, refresh logic). - Deleted internal/executor Gemini OAuth support, including bearer token handling and runtime API logic. - Purged all tests, configs, and command-line flags specific to Gemini OAuth flows. - Updated documentation and aliases to reflect Gemini removal. - Renamed `parseRetryDelay` to `ParseRetryDelay` and `deleteJSONField` to `DeleteJSONField`. - Updated references in `antigravity_executor` and tests to use the new `helps` package. - Adjusted import paths and test cases to ensure compatibility with the new location. - Updated README files to reflect changes in the retry logic references. - Updated `.github/ISSUE_TEMPLATE/bug_report.md` to remove deprecated Gemini CLI mention.
81 lines
2.1 KiB
Go
81 lines
2.1 KiB
Go
package helps
|
|
|
|
import (
|
|
"fmt"
|
|
"regexp"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/tidwall/gjson"
|
|
"github.com/tidwall/sjson"
|
|
)
|
|
|
|
// DeleteJSONField removes a top-level or nested JSON field from a payload.
|
|
func DeleteJSONField(body []byte, key string) []byte {
|
|
if key == "" || len(body) == 0 {
|
|
return body
|
|
}
|
|
updated, err := sjson.DeleteBytes(body, key)
|
|
if err != nil {
|
|
return body
|
|
}
|
|
return updated
|
|
}
|
|
|
|
// ParseRetryDelay extracts the retry delay from a Google API 429 error response.
|
|
func ParseRetryDelay(errorBody []byte) (*time.Duration, error) {
|
|
details := gjson.GetBytes(errorBody, "error.details")
|
|
if details.Exists() && details.IsArray() {
|
|
for _, detail := range details.Array() {
|
|
if detail.Get("@type").String() != "type.googleapis.com/google.rpc.RetryInfo" {
|
|
continue
|
|
}
|
|
retryDelay := detail.Get("retryDelay").String()
|
|
if retryDelay == "" {
|
|
continue
|
|
}
|
|
duration, err := time.ParseDuration(retryDelay)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to parse duration")
|
|
}
|
|
return &duration, nil
|
|
}
|
|
|
|
for _, detail := range details.Array() {
|
|
if detail.Get("@type").String() != "type.googleapis.com/google.rpc.ErrorInfo" {
|
|
continue
|
|
}
|
|
quotaResetDelay := detail.Get("metadata.quotaResetDelay").String()
|
|
if quotaResetDelay == "" {
|
|
continue
|
|
}
|
|
duration, err := time.ParseDuration(quotaResetDelay)
|
|
if err == nil {
|
|
return &duration, nil
|
|
}
|
|
}
|
|
}
|
|
|
|
message := gjson.GetBytes(errorBody, "error.message").String()
|
|
if message != "" {
|
|
re := regexp.MustCompile(`after\s+(\d+)s\.?`)
|
|
if matches := re.FindStringSubmatch(message); len(matches) > 1 {
|
|
seconds, err := strconv.Atoi(matches[1])
|
|
if err == nil {
|
|
duration := time.Duration(seconds) * time.Second
|
|
return &duration, nil
|
|
}
|
|
}
|
|
reHuman := regexp.MustCompile(`after\s+((?:\d+h)?(?:\d+m)?(?:\d+s)?)\.?`)
|
|
if matches := reHuman.FindStringSubmatch(strings.ToLower(message)); len(matches) > 1 {
|
|
duration, err := time.ParseDuration(matches[1])
|
|
if err == nil && duration > 0 {
|
|
return &duration, nil
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil, fmt.Errorf("no RetryInfo found")
|
|
}
|