Skip to content

Commit 973e059

Browse files
Merge upstream/main (auto-sync feat/copilot)
- bcbb949 feat(client): add cluster node failover and improve reconnection handling - 437aa87 feat(api): add dynamic handler for Gemini models with home integration - 3a9fb37 fix(home): implement home dispatch headers and enhance Gemini model handling
2 parents 65aa351 + 3a9fb37 commit 973e059

4 files changed

Lines changed: 546 additions & 68 deletions

File tree

internal/api/server.go

Lines changed: 146 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -407,9 +407,9 @@ func (s *Server) setupRoutes() {
407407
v1beta := s.engine.Group("/v1beta")
408408
v1beta.Use(AuthMiddleware(s.accessManager))
409409
{
410-
v1beta.GET("/models", geminiHandlers.GeminiModels)
410+
v1beta.GET("/models", s.geminiModelsHandler(geminiHandlers))
411411
v1beta.POST("/models/*action", geminiHandlers.GeminiHandler)
412-
v1beta.GET("/models/*action", geminiHandlers.GeminiGetHandler)
412+
v1beta.GET("/models/*action", s.geminiGetHandler(geminiHandlers))
413413
}
414414

415415
// Root endpoint
@@ -842,6 +842,28 @@ func (s *Server) unifiedModelsHandler(openaiHandler *openai.OpenAIAPIHandler, cl
842842
}
843843
}
844844

845+
func (s *Server) geminiModelsHandler(geminiHandler *gemini.GeminiAPIHandler) gin.HandlerFunc {
846+
return func(c *gin.Context) {
847+
if s != nil && s.cfg != nil && s.cfg.Home.Enabled {
848+
s.handleHomeGeminiModels(c)
849+
return
850+
}
851+
852+
geminiHandler.GeminiModels(c)
853+
}
854+
}
855+
856+
func (s *Server) geminiGetHandler(geminiHandler *gemini.GeminiAPIHandler) gin.HandlerFunc {
857+
return func(c *gin.Context) {
858+
if s != nil && s.cfg != nil && s.cfg.Home.Enabled {
859+
s.handleHomeGeminiModel(c)
860+
return
861+
}
862+
863+
geminiHandler.GeminiGetHandler(c)
864+
}
865+
}
866+
845867
type homeModelEntry struct {
846868
id string
847869
created int64
@@ -850,39 +872,8 @@ type homeModelEntry struct {
850872
}
851873

852874
func (s *Server) handleHomeModels(c *gin.Context) {
853-
if s == nil || c == nil || c.Request == nil {
854-
return
855-
}
856-
client := home.Current()
857-
if client == nil {
858-
c.JSON(http.StatusServiceUnavailable, handlers.ErrorResponse{
859-
Error: handlers.ErrorDetail{
860-
Message: "home control center unavailable",
861-
Type: "server_error",
862-
},
863-
})
864-
return
865-
}
866-
867-
raw, errGet := client.GetModels(c.Request.Context())
868-
if errGet != nil {
869-
c.JSON(http.StatusBadGateway, handlers.ErrorResponse{
870-
Error: handlers.ErrorDetail{
871-
Message: errGet.Error(),
872-
Type: "server_error",
873-
},
874-
})
875-
return
876-
}
877-
878-
entries, errDecode := decodeHomeModels(raw)
879-
if errDecode != nil {
880-
c.JSON(http.StatusBadGateway, handlers.ErrorResponse{
881-
Error: handlers.ErrorDetail{
882-
Message: errDecode.Error(),
883-
Type: "server_error",
884-
},
885-
})
875+
entries, ok := s.loadHomeModelEntries(c)
876+
if !ok {
886877
return
887878
}
888879

@@ -908,10 +899,10 @@ func (s *Server) handleHomeModels(c *gin.Context) {
908899
firstID := ""
909900
lastID := ""
910901
if len(out) > 0 {
911-
if id, ok := out[0]["id"].(string); ok {
902+
if id, okID := out[0]["id"].(string); okID {
912903
firstID = id
913904
}
914-
if id, ok := out[len(out)-1]["id"].(string); ok {
905+
if id, okID := out[len(out)-1]["id"].(string); okID {
915906
lastID = id
916907
}
917908
}
@@ -944,6 +935,115 @@ func (s *Server) handleHomeModels(c *gin.Context) {
944935
})
945936
}
946937

938+
func (s *Server) handleHomeGeminiModels(c *gin.Context) {
939+
entries, ok := s.loadHomeModelEntries(c)
940+
if !ok {
941+
return
942+
}
943+
944+
c.JSON(http.StatusOK, gin.H{
945+
"models": formatHomeGeminiModels(entries),
946+
})
947+
}
948+
949+
func (s *Server) handleHomeGeminiModel(c *gin.Context) {
950+
entries, ok := s.loadHomeModelEntries(c)
951+
if !ok {
952+
return
953+
}
954+
955+
action := strings.TrimPrefix(c.Param("action"), "/")
956+
action = strings.TrimSpace(action)
957+
for _, entry := range entries {
958+
if homeGeminiModelMatches(entry, action) {
959+
c.JSON(http.StatusOK, formatHomeGeminiModel(entry))
960+
return
961+
}
962+
}
963+
964+
c.JSON(http.StatusNotFound, handlers.ErrorResponse{
965+
Error: handlers.ErrorDetail{
966+
Message: "Not Found",
967+
Type: "not_found",
968+
},
969+
})
970+
}
971+
972+
func (s *Server) loadHomeModelEntries(c *gin.Context) ([]homeModelEntry, bool) {
973+
if s == nil || c == nil || c.Request == nil {
974+
return nil, false
975+
}
976+
client := home.Current()
977+
if client == nil {
978+
c.JSON(http.StatusServiceUnavailable, handlers.ErrorResponse{
979+
Error: handlers.ErrorDetail{
980+
Message: "home control center unavailable",
981+
Type: "server_error",
982+
},
983+
})
984+
return nil, false
985+
}
986+
987+
raw, errGet := client.GetModels(c.Request.Context())
988+
if errGet != nil {
989+
c.JSON(http.StatusBadGateway, handlers.ErrorResponse{
990+
Error: handlers.ErrorDetail{
991+
Message: errGet.Error(),
992+
Type: "server_error",
993+
},
994+
})
995+
return nil, false
996+
}
997+
998+
entries, errDecode := decodeHomeModels(raw)
999+
if errDecode != nil {
1000+
c.JSON(http.StatusBadGateway, handlers.ErrorResponse{
1001+
Error: handlers.ErrorDetail{
1002+
Message: errDecode.Error(),
1003+
Type: "server_error",
1004+
},
1005+
})
1006+
return nil, false
1007+
}
1008+
1009+
return entries, true
1010+
}
1011+
1012+
func formatHomeGeminiModels(entries []homeModelEntry) []map[string]any {
1013+
out := make([]map[string]any, 0, len(entries))
1014+
for _, entry := range entries {
1015+
out = append(out, formatHomeGeminiModel(entry))
1016+
}
1017+
return out
1018+
}
1019+
1020+
func formatHomeGeminiModel(entry homeModelEntry) map[string]any {
1021+
name := entry.id
1022+
if !strings.HasPrefix(name, "models/") {
1023+
name = "models/" + name
1024+
}
1025+
displayName := entry.displayName
1026+
if displayName == "" {
1027+
displayName = entry.id
1028+
}
1029+
return map[string]any{
1030+
"name": name,
1031+
"displayName": displayName,
1032+
"description": displayName,
1033+
"supportedGenerationMethods": []string{"generateContent"},
1034+
}
1035+
}
1036+
1037+
func homeGeminiModelMatches(entry homeModelEntry, action string) bool {
1038+
id := strings.TrimSpace(entry.id)
1039+
if id == "" || action == "" {
1040+
return false
1041+
}
1042+
normalizedAction := strings.TrimPrefix(action, "models/")
1043+
normalizedID := strings.TrimPrefix(id, "models/")
1044+
return action == id || action == "models/"+id || normalizedAction == normalizedID
1045+
}
1046+
9471047
func decodeHomeModels(raw []byte) ([]homeModelEntry, error) {
9481048
if len(raw) == 0 {
9491049
return nil, fmt.Errorf("home models payload is empty")
@@ -963,6 +1063,11 @@ func decodeHomeModels(raw []byte) ([]homeModelEntry, error) {
9631063
for _, model := range models {
9641064
id, _ := model["id"].(string)
9651065
id = strings.TrimSpace(id)
1066+
if id == "" {
1067+
name, _ := model["name"].(string)
1068+
name = strings.TrimSpace(name)
1069+
id = strings.TrimPrefix(name, "models/")
1070+
}
9661071
if id == "" {
9671072
continue
9681073
}
@@ -989,6 +1094,10 @@ func decodeHomeModels(raw []byte) ([]homeModelEntry, error) {
9891094
ownedBy = strings.TrimSpace(ownedBy)
9901095
displayName, _ := model["display_name"].(string)
9911096
displayName = strings.TrimSpace(displayName)
1097+
if displayName == "" {
1098+
displayName, _ = model["displayName"].(string)
1099+
displayName = strings.TrimSpace(displayName)
1100+
}
9921101

9931102
out = append(out, homeModelEntry{
9941103
id: id,

0 commit comments

Comments
 (0)