mirror of
https://github.com/router-for-me/CLIProxyAPI.git
synced 2026-02-03 04:50:52 +08:00
- Introduced request and response translation functions to enable compatibility between OpenAI Chat Completions API and Antigravity. - Registered translation utilities for both streaming and non-streaming scenarios. - Added support for reasoning content, tool calls, and metadata handling. - Established request normalization and embedding for Antigravity-compatible payloads. - Added new fields to `Params` struct for better tracking of finish reasons, usage metadata, and tool usage. - Refactored handling of response transitions, final events, and state-driven logic in `ConvertAntigravityResponseToClaude`. - Introduced `appendFinalEvents` and `resolveStopReason` helper functions for cleaner separation of concerns. - Added `TotalTokenCount` field to `Params` struct for enhanced token tracking. - Updated token count calculations to fallback on `TotalTokenCount` when specific counts are missing. - Introduced `hasNonZeroUsageMetadata` function to validate presence of token data in `usage_metadata`.
87 lines
3.7 KiB
Go
87 lines
3.7 KiB
Go
// Package gemini provides request translation functionality for Gemini to Gemini CLI API compatibility.
|
|
// It handles parsing and transforming Gemini API requests into Gemini CLI API format,
|
|
// extracting model information, system instructions, message contents, and tool declarations.
|
|
// The package performs JSON data transformation to ensure compatibility
|
|
// between Gemini API format and Gemini CLI API's expected format.
|
|
package gemini
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"fmt"
|
|
|
|
"github.com/tidwall/gjson"
|
|
"github.com/tidwall/sjson"
|
|
)
|
|
|
|
// ConvertAntigravityResponseToGemini parses and transforms a Gemini CLI API request into Gemini API format.
|
|
// 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 Gemini API.
|
|
// The function performs the following transformations:
|
|
// 1. Extracts the response data from the request
|
|
// 2. Handles alternative response formats
|
|
// 3. Processes array responses by extracting individual response objects
|
|
//
|
|
// Parameters:
|
|
// - ctx: The context for the request, used for cancellation and timeout handling
|
|
// - modelName: The name of the model to use for the request (unused in current implementation)
|
|
// - rawJSON: The raw JSON request data from the Gemini CLI API
|
|
// - param: A pointer to a parameter object for the conversion (unused in current implementation)
|
|
//
|
|
// Returns:
|
|
// - []string: The transformed request data in Gemini API format
|
|
func ConvertAntigravityResponseToGemini(ctx context.Context, _ string, originalRequestRawJSON, requestRawJSON, rawJSON []byte, _ *any) []string {
|
|
if bytes.HasPrefix(rawJSON, []byte("data:")) {
|
|
rawJSON = bytes.TrimSpace(rawJSON[5:])
|
|
}
|
|
|
|
if alt, ok := ctx.Value("alt").(string); ok {
|
|
var chunk []byte
|
|
if alt == "" {
|
|
responseResult := gjson.GetBytes(rawJSON, "response")
|
|
if responseResult.Exists() {
|
|
chunk = []byte(responseResult.Raw)
|
|
}
|
|
} else {
|
|
chunkTemplate := "[]"
|
|
responseResult := gjson.ParseBytes(chunk)
|
|
if responseResult.IsArray() {
|
|
responseResultItems := responseResult.Array()
|
|
for i := 0; i < len(responseResultItems); i++ {
|
|
responseResultItem := responseResultItems[i]
|
|
if responseResultItem.Get("response").Exists() {
|
|
chunkTemplate, _ = sjson.SetRaw(chunkTemplate, "-1", responseResultItem.Get("response").Raw)
|
|
}
|
|
}
|
|
}
|
|
chunk = []byte(chunkTemplate)
|
|
}
|
|
return []string{string(chunk)}
|
|
}
|
|
return []string{}
|
|
}
|
|
|
|
// ConvertAntigravityResponseToGeminiNonStream converts a non-streaming Gemini CLI request to a non-streaming Gemini response.
|
|
// This function processes the complete Gemini CLI request and transforms it into a single Gemini-compatible
|
|
// JSON response. It extracts the response data from the request and returns it in the expected format.
|
|
//
|
|
// Parameters:
|
|
// - ctx: The context for the request, used for cancellation and timeout handling
|
|
// - modelName: The name of the model being used for the response (unused in current implementation)
|
|
// - rawJSON: The raw JSON request data from the Gemini CLI API
|
|
// - param: A pointer to a parameter object for the conversion (unused in current implementation)
|
|
//
|
|
// Returns:
|
|
// - string: A Gemini-compatible JSON response containing the response data
|
|
func ConvertAntigravityResponseToGeminiNonStream(_ context.Context, _ string, originalRequestRawJSON, requestRawJSON, rawJSON []byte, _ *any) string {
|
|
responseResult := gjson.GetBytes(rawJSON, "response")
|
|
if responseResult.Exists() {
|
|
return responseResult.Raw
|
|
}
|
|
return string(rawJSON)
|
|
}
|
|
|
|
func GeminiTokenCount(ctx context.Context, count int64) string {
|
|
return fmt.Sprintf(`{"totalTokens":%d,"promptTokensDetails":[{"modality":"TEXT","tokenCount":%d}]}`, count, count)
|
|
}
|