From e216d267318e4f769a51e38cab1409aa7b1e8edd Mon Sep 17 00:00:00 2001 From: Thurston Sandberg Date: Wed, 3 Dec 2025 04:40:32 -0500 Subject: [PATCH 1/5] fix(amp): add missing /auth/* and /api/tab/* proxy routes --- internal/api/modules/amp/routes.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/internal/api/modules/amp/routes.go b/internal/api/modules/amp/routes.go index 02f518a1..b7105a14 100644 --- a/internal/api/modules/amp/routes.go +++ b/internal/api/modules/amp/routes.go @@ -110,6 +110,8 @@ func (m *AmpModule) registerManagementRoutes(engine *gin.Engine, baseHandler *ha ampAPI.Any("/threads/*path", proxyHandler) ampAPI.Any("/otel", proxyHandler) ampAPI.Any("/otel/*path", proxyHandler) + ampAPI.Any("/tab", proxyHandler) + ampAPI.Any("/tab/*path", proxyHandler) // Root-level routes that AMP CLI expects without /api prefix // These need the same security middleware as the /api/* routes @@ -119,6 +121,12 @@ func (m *AmpModule) registerManagementRoutes(engine *gin.Engine, baseHandler *ha } engine.GET("/threads.rss", append(rootMiddleware, proxyHandler)...) + // Root-level auth routes for CLI login flow + // Amp uses multiple auth routes: /auth/cli-login, /auth/callback, /auth/sign-in, /auth/logout + // We proxy all /auth/* to support the complete OAuth flow + engine.Any("/auth", append(rootMiddleware, proxyHandler)...) + engine.Any("/auth/*path", append(rootMiddleware, proxyHandler)...) + // Google v1beta1 passthrough with OAuth fallback // AMP CLI uses non-standard paths like /publishers/google/models/... // We bridge these to our standard Gemini handler to enable local OAuth. From 94ec772521ea05333f9fcb876d7623c83f22ae2e Mon Sep 17 00:00:00 2001 From: Thurston Sandberg Date: Wed, 3 Dec 2025 05:03:25 -0500 Subject: [PATCH 2/5] test(amp): add tests for /auth/* and /api/tab/* routes --- internal/api/modules/amp/routes_test.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/internal/api/modules/amp/routes_test.go b/internal/api/modules/amp/routes_test.go index 51bd7abd..89e43506 100644 --- a/internal/api/modules/amp/routes_test.go +++ b/internal/api/modules/amp/routes_test.go @@ -39,6 +39,11 @@ func TestRegisterManagementRoutes(t *testing.T) { {"/api/threads", http.MethodGet}, {"/threads.rss", http.MethodGet}, // Root-level route (no /api prefix) {"/api/otel", http.MethodGet}, + {"/api/tab", http.MethodGet}, + {"/api/tab/some/path", http.MethodGet}, + {"/auth", http.MethodGet}, // Root-level auth route + {"/auth/cli-login", http.MethodGet}, // CLI login flow + {"/auth/callback", http.MethodGet}, // OAuth callback // Google v1beta1 bridge should still proxy non-model requests (GET) and allow POST {"/api/provider/google/v1beta1/models", http.MethodGet}, {"/api/provider/google/v1beta1/models", http.MethodPost}, From b5de004c01112b9c850bfe47aab4817bcf436273 Mon Sep 17 00:00:00 2001 From: hkfires <10558748+hkfires@users.noreply.github.com> Date: Wed, 3 Dec 2025 18:35:08 +0800 Subject: [PATCH 3/5] refactor(api): remove legacy generative-language-api-key endpoints and duplicate GetConfigYAML --- .../api/handlers/management/config_basic.go | 23 +------ .../api/handlers/management/config_lists.go | 64 ------------------- internal/api/server.go | 7 +- 3 files changed, 3 insertions(+), 91 deletions(-) diff --git a/internal/api/handlers/management/config_basic.go b/internal/api/handlers/management/config_basic.go index 0f76b5a3..5843c5b8 100644 --- a/internal/api/handlers/management/config_basic.go +++ b/internal/api/handlers/management/config_basic.go @@ -20,25 +20,6 @@ func (h *Handler) GetConfig(c *gin.Context) { c.JSON(200, &cfgCopy) } -func (h *Handler) GetConfigYAML(c *gin.Context) { - data, err := os.ReadFile(h.configFilePath) - if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": "read_failed", "message": err.Error()}) - return - } - var node yaml.Node - if err = yaml.Unmarshal(data, &node); err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": "parse_failed", "message": err.Error()}) - return - } - c.Header("Content-Type", "application/yaml; charset=utf-8") - c.Header("Vary", "format, Accept") - enc := yaml.NewEncoder(c.Writer) - enc.SetIndent(2) - _ = enc.Encode(&node) - _ = enc.Close() -} - func WriteConfig(path string, data []byte) error { data = config.NormalizeCommentIndentation(data) f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644) @@ -110,9 +91,9 @@ func (h *Handler) PutConfigYAML(c *gin.Context) { c.JSON(http.StatusOK, gin.H{"ok": true, "changed": []string{"config"}}) } -// GetConfigFile returns the raw config.yaml file bytes without re-encoding. +// GetConfigYAML returns the raw config.yaml file bytes without re-encoding. // It preserves comments and original formatting/styles. -func (h *Handler) GetConfigFile(c *gin.Context) { +func (h *Handler) GetConfigYAML(c *gin.Context) { data, err := os.ReadFile(h.configFilePath) if err != nil { if os.IsNotExist(err) { diff --git a/internal/api/handlers/management/config_lists.go b/internal/api/handlers/management/config_lists.go index c5cbfa43..8f4c4037 100644 --- a/internal/api/handlers/management/config_lists.go +++ b/internal/api/handlers/management/config_lists.go @@ -104,52 +104,6 @@ func (h *Handler) deleteFromStringList(c *gin.Context, target *[]string, after f c.JSON(400, gin.H{"error": "missing index or value"}) } -func sanitizeStringSlice(in []string) []string { - out := make([]string, 0, len(in)) - for i := range in { - if trimmed := strings.TrimSpace(in[i]); trimmed != "" { - out = append(out, trimmed) - } - } - return out -} - -func geminiKeyStringsFromConfig(cfg *config.Config) []string { - if cfg == nil || len(cfg.GeminiKey) == 0 { - return nil - } - out := make([]string, 0, len(cfg.GeminiKey)) - for i := range cfg.GeminiKey { - if key := strings.TrimSpace(cfg.GeminiKey[i].APIKey); key != "" { - out = append(out, key) - } - } - return out -} - -func (h *Handler) applyLegacyKeys(keys []string) { - if h == nil || h.cfg == nil { - return - } - sanitized := sanitizeStringSlice(keys) - existing := make(map[string]config.GeminiKey, len(h.cfg.GeminiKey)) - for _, entry := range h.cfg.GeminiKey { - if key := strings.TrimSpace(entry.APIKey); key != "" { - existing[key] = entry - } - } - newList := make([]config.GeminiKey, 0, len(sanitized)) - for _, key := range sanitized { - if entry, ok := existing[key]; ok { - newList = append(newList, entry) - } else { - newList = append(newList, config.GeminiKey{APIKey: key}) - } - } - h.cfg.GeminiKey = newList - h.cfg.SanitizeGeminiKeys() -} - // api-keys func (h *Handler) GetAPIKeys(c *gin.Context) { c.JSON(200, gin.H{"api-keys": h.cfg.APIKeys}) } func (h *Handler) PutAPIKeys(c *gin.Context) { @@ -165,24 +119,6 @@ func (h *Handler) DeleteAPIKeys(c *gin.Context) { h.deleteFromStringList(c, &h.cfg.APIKeys, func() { h.cfg.Access.Providers = nil }) } -// generative-language-api-key -func (h *Handler) GetGlKeys(c *gin.Context) { - c.JSON(200, gin.H{"generative-language-api-key": geminiKeyStringsFromConfig(h.cfg)}) -} -func (h *Handler) PutGlKeys(c *gin.Context) { - h.putStringList(c, func(v []string) { - h.applyLegacyKeys(v) - }, nil) -} -func (h *Handler) PatchGlKeys(c *gin.Context) { - target := append([]string(nil), geminiKeyStringsFromConfig(h.cfg)...) - h.patchStringList(c, &target, func() { h.applyLegacyKeys(target) }) -} -func (h *Handler) DeleteGlKeys(c *gin.Context) { - target := append([]string(nil), geminiKeyStringsFromConfig(h.cfg)...) - h.deleteFromStringList(c, &target, func() { h.applyLegacyKeys(target) }) -} - // gemini-api-key: []GeminiKey func (h *Handler) GetGeminiKeys(c *gin.Context) { c.JSON(200, gin.H{"gemini-api-key": h.cfg.GeminiKey}) diff --git a/internal/api/server.go b/internal/api/server.go index 6866b4cf..c4d6ad8f 100644 --- a/internal/api/server.go +++ b/internal/api/server.go @@ -470,8 +470,8 @@ func (s *Server) registerManagementRoutes() { { mgmt.GET("/usage", s.mgmt.GetUsageStatistics) mgmt.GET("/config", s.mgmt.GetConfig) + mgmt.GET("/config.yaml", s.mgmt.GetConfigYAML) mgmt.PUT("/config.yaml", s.mgmt.PutConfigYAML) - mgmt.GET("/config.yaml", s.mgmt.GetConfigFile) mgmt.GET("/debug", s.mgmt.GetDebug) mgmt.PUT("/debug", s.mgmt.PutDebug) @@ -503,11 +503,6 @@ func (s *Server) registerManagementRoutes() { mgmt.PATCH("/api-keys", s.mgmt.PatchAPIKeys) mgmt.DELETE("/api-keys", s.mgmt.DeleteAPIKeys) - mgmt.GET("/generative-language-api-key", s.mgmt.GetGlKeys) - mgmt.PUT("/generative-language-api-key", s.mgmt.PutGlKeys) - mgmt.PATCH("/generative-language-api-key", s.mgmt.PatchGlKeys) - mgmt.DELETE("/generative-language-api-key", s.mgmt.DeleteGlKeys) - mgmt.GET("/gemini-api-key", s.mgmt.GetGeminiKeys) mgmt.PUT("/gemini-api-key", s.mgmt.PutGeminiKeys) mgmt.PATCH("/gemini-api-key", s.mgmt.PatchGeminiKey) From 373ea8d7e412b29c93df3eeaeb4a2b29c29645bf Mon Sep 17 00:00:00 2001 From: Thurston Sandberg Date: Wed, 3 Dec 2025 05:54:38 -0500 Subject: [PATCH 4/5] fix(logging): handle nil caller in LogFormatter to prevent panic --- internal/logging/global_logger.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/internal/logging/global_logger.go b/internal/logging/global_logger.go index 9d4e1fc9..28fde213 100644 --- a/internal/logging/global_logger.go +++ b/internal/logging/global_logger.go @@ -38,7 +38,13 @@ func (m *LogFormatter) Format(entry *log.Entry) ([]byte, error) { timestamp := entry.Time.Format("2006-01-02 15:04:05") message := strings.TrimRight(entry.Message, "\r\n") - formatted := fmt.Sprintf("[%s] [%s] [%s:%d] %s\n", timestamp, entry.Level, filepath.Base(entry.Caller.File), entry.Caller.Line, message) + + var formatted string + if entry.Caller != nil { + formatted = fmt.Sprintf("[%s] [%s] [%s:%d] %s\n", timestamp, entry.Level, filepath.Base(entry.Caller.File), entry.Caller.Line, message) + } else { + formatted = fmt.Sprintf("[%s] [%s] %s\n", timestamp, entry.Level, message) + } buffer.WriteString(formatted) return buffer.Bytes(), nil From 6a2906e3e5aa1836144e19904e172234751d8594 Mon Sep 17 00:00:00 2001 From: Luis Pater Date: Thu, 4 Dec 2025 16:13:13 +0800 Subject: [PATCH 5/5] **feat(antigravity): add support for Claude-Opus-4-5-Thinking model** --- internal/runtime/executor/antigravity_executor.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/internal/runtime/executor/antigravity_executor.go b/internal/runtime/executor/antigravity_executor.go index fd79c394..a667a4d9 100644 --- a/internal/runtime/executor/antigravity_executor.go +++ b/internal/runtime/executor/antigravity_executor.go @@ -734,6 +734,8 @@ func modelName2Alias(modelName string) string { return "gemini-claude-sonnet-4-5" case "claude-sonnet-4-5-thinking": return "gemini-claude-sonnet-4-5-thinking" + case "claude-opus-4-5-thinking": + return "gemini-claude-opus-4-5-thinking" case "chat_20706", "chat_23310", "gemini-2.5-flash-thinking", "gemini-3-pro-low", "gemini-2.5-pro": return "" default: @@ -753,6 +755,8 @@ func alias2ModelName(modelName string) string { return "claude-sonnet-4-5" case "gemini-claude-sonnet-4-5-thinking": return "claude-sonnet-4-5-thinking" + case "gemini-claude-opus-4-5-thinking": + return "claude-opus-4-5-thinking" default: return modelName }