2025-12-25 06:43:35 -08:00
package repository
import (
"context"
"fmt"
"time"
"github.com/Wei-Shaw/sub2api/internal/pkg/geminicli"
2026-02-05 20:13:06 +08:00
"github.com/Wei-Shaw/sub2api/internal/pkg/googleapi"
2025-12-25 21:52:39 -08:00
"github.com/Wei-Shaw/sub2api/internal/service"
2025-12-25 06:43:35 -08:00
"github.com/imroc/req/v3"
)
type geminiCliCodeAssistClient struct {
baseURL string
}
2025-12-25 21:52:39 -08:00
func NewGeminiCliCodeAssistClient ( ) service . GeminiCliCodeAssistClient {
2025-12-25 06:43:35 -08:00
return & geminiCliCodeAssistClient { baseURL : geminicli . GeminiCliBaseURL }
}
func ( c * geminiCliCodeAssistClient ) LoadCodeAssist ( ctx context . Context , accessToken , proxyURL string , reqBody * geminicli . LoadCodeAssistRequest ) ( * geminicli . LoadCodeAssistResponse , error ) {
if reqBody == nil {
reqBody = defaultLoadCodeAssistRequest ( )
}
var out geminicli . LoadCodeAssistResponse
2026-03-02 15:53:26 +08:00
client , err := createGeminiCliReqClient ( proxyURL )
if err != nil {
return nil , fmt . Errorf ( "create HTTP client: %w" , err )
}
resp , err := client . R ( ) .
2025-12-25 06:43:35 -08:00
SetContext ( ctx ) .
SetHeader ( "Authorization" , "Bearer " + accessToken ) .
SetHeader ( "Content-Type" , "application/json" ) .
SetHeader ( "User-Agent" , geminicli . GeminiCLIUserAgent ) .
SetBody ( reqBody ) .
SetSuccessResult ( & out ) .
Post ( c . baseURL + "/v1internal:loadCodeAssist" )
if err != nil {
2025-12-25 21:24:35 -08:00
fmt . Printf ( "[CodeAssist] LoadCodeAssist request error: %v\n" , err )
2025-12-25 06:43:35 -08:00
return nil , fmt . Errorf ( "request failed: %w" , err )
}
if ! resp . IsSuccessState ( ) {
2026-02-05 20:13:06 +08:00
body := resp . String ( )
sanitizedBody := geminicli . SanitizeBodyForLogs ( body )
fmt . Printf ( "[CodeAssist] LoadCodeAssist failed: status %d, body: %s\n" , resp . StatusCode , sanitizedBody )
// Check if this is a SERVICE_DISABLED error and extract activation URL
if googleapi . IsServiceDisabledError ( body ) {
activationURL := googleapi . ExtractActivationURL ( body )
if activationURL != "" {
2026-02-05 20:47:15 +08:00
return nil , fmt . Errorf ( "gemini API not enabled for this project, please enable it by visiting: %s\n\nAfter enabling the API, wait a few minutes for the changes to propagate, then try again" , activationURL )
2026-02-05 20:13:06 +08:00
}
2026-02-05 20:47:15 +08:00
return nil , fmt . Errorf ( "gemini API not enabled for this project, please enable it in the Google Cloud Console at: https://console.cloud.google.com/apis/library/cloudaicompanion.googleapis.com" )
2026-02-05 20:13:06 +08:00
}
return nil , fmt . Errorf ( "loadCodeAssist failed: status %d, body: %s" , resp . StatusCode , sanitizedBody )
2025-12-25 06:43:35 -08:00
}
2025-12-25 21:24:35 -08:00
fmt . Printf ( "[CodeAssist] LoadCodeAssist success: status %d, response: %+v\n" , resp . StatusCode , out )
2025-12-25 06:43:35 -08:00
return & out , nil
}
func ( c * geminiCliCodeAssistClient ) OnboardUser ( ctx context . Context , accessToken , proxyURL string , reqBody * geminicli . OnboardUserRequest ) ( * geminicli . OnboardUserResponse , error ) {
if reqBody == nil {
reqBody = defaultOnboardUserRequest ( )
}
2025-12-25 21:24:35 -08:00
fmt . Printf ( "[CodeAssist] OnboardUser request body: %+v\n" , reqBody )
2025-12-25 06:43:35 -08:00
var out geminicli . OnboardUserResponse
2026-03-02 15:53:26 +08:00
client , err := createGeminiCliReqClient ( proxyURL )
if err != nil {
return nil , fmt . Errorf ( "create HTTP client: %w" , err )
}
resp , err := client . R ( ) .
2025-12-25 06:43:35 -08:00
SetContext ( ctx ) .
SetHeader ( "Authorization" , "Bearer " + accessToken ) .
SetHeader ( "Content-Type" , "application/json" ) .
SetHeader ( "User-Agent" , geminicli . GeminiCLIUserAgent ) .
SetBody ( reqBody ) .
SetSuccessResult ( & out ) .
Post ( c . baseURL + "/v1internal:onboardUser" )
if err != nil {
2025-12-25 21:24:35 -08:00
fmt . Printf ( "[CodeAssist] OnboardUser request error: %v\n" , err )
2025-12-25 06:43:35 -08:00
return nil , fmt . Errorf ( "request failed: %w" , err )
}
if ! resp . IsSuccessState ( ) {
2026-02-05 20:13:06 +08:00
body := resp . String ( )
sanitizedBody := geminicli . SanitizeBodyForLogs ( body )
fmt . Printf ( "[CodeAssist] OnboardUser failed: status %d, body: %s\n" , resp . StatusCode , sanitizedBody )
// Check if this is a SERVICE_DISABLED error and extract activation URL
if googleapi . IsServiceDisabledError ( body ) {
activationURL := googleapi . ExtractActivationURL ( body )
if activationURL != "" {
2026-02-05 20:47:15 +08:00
return nil , fmt . Errorf ( "gemini API not enabled for this project, please enable it by visiting: %s\n\nAfter enabling the API, wait a few minutes for the changes to propagate, then try again" , activationURL )
2026-02-05 20:13:06 +08:00
}
2026-02-05 20:47:15 +08:00
return nil , fmt . Errorf ( "gemini API not enabled for this project, please enable it in the Google Cloud Console at: https://console.cloud.google.com/apis/library/cloudaicompanion.googleapis.com" )
2026-02-05 20:13:06 +08:00
}
return nil , fmt . Errorf ( "onboardUser failed: status %d, body: %s" , resp . StatusCode , sanitizedBody )
2025-12-25 06:43:35 -08:00
}
2025-12-25 21:24:35 -08:00
fmt . Printf ( "[CodeAssist] OnboardUser success: status %d, response: %+v\n" , resp . StatusCode , out )
2025-12-25 06:43:35 -08:00
return & out , nil
}
2026-03-02 15:53:26 +08:00
func createGeminiCliReqClient ( proxyURL string ) ( * req . Client , error ) {
2025-12-31 08:50:12 +08:00
return getSharedReqClient ( reqClientOptions {
ProxyURL : proxyURL ,
Timeout : 30 * time . Second ,
} )
2025-12-25 06:43:35 -08:00
}
func defaultLoadCodeAssistRequest ( ) * geminicli . LoadCodeAssistRequest {
return & geminicli . LoadCodeAssistRequest {
Metadata : geminicli . LoadCodeAssistMetadata {
IDEType : "ANTIGRAVITY" ,
Platform : "PLATFORM_UNSPECIFIED" ,
PluginType : "GEMINI" ,
} ,
}
}
func defaultOnboardUserRequest ( ) * geminicli . OnboardUserRequest {
return & geminicli . OnboardUserRequest {
TierID : "LEGACY" ,
Metadata : geminicli . LoadCodeAssistMetadata {
IDEType : "ANTIGRAVITY" ,
Platform : "PLATFORM_UNSPECIFIED" ,
PluginType : "GEMINI" ,
} ,
}
}