From c7343d2aa26274fda4d95646ba7315c5f59f4e49 Mon Sep 17 00:00:00 2001 From: TT <92159997+ssharkkky@users.noreply.github.com> Date: Sat, 5 Sep 2026 23:30:45 +0800 Subject: [PATCH] fix(monitors): send explicit user role in Gemini monitor probes The Antigravity native Gemini route (generateContent) expects each contents entry to carry an explicit "user" role, matching the request shape used by the established Antigravity account-test flow. Without it the probe body is rejected with 400 INVALID_ARGUMENT, so Gemini channel monitors report false failures. Add the explicit role to the Gemini provider adapter body and cover it with a regression test that parses the generated request body. --- .../service/channel_monitor_checker.go | 2 +- .../channel_monitor_checker_body_test.go | 23 +++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/backend/internal/service/channel_monitor_checker.go b/backend/internal/service/channel_monitor_checker.go index 71177db0bd..23388405a0 100644 --- a/backend/internal/service/channel_monitor_checker.go +++ b/backend/internal/service/channel_monitor_checker.go @@ -198,7 +198,7 @@ var providerAdapters = map[string]providerAdapter{ buildBody: func(_, prompt string) ([]byte, error) { return json.Marshal(map[string]any{ "contents": []map[string]any{ - {"parts": []map[string]any{{"text": prompt}}}, + {"role": "user", "parts": []map[string]any{{"text": prompt}}}, }, "generationConfig": map[string]any{"maxOutputTokens": monitorChallengeMaxTokens}, }) diff --git a/backend/internal/service/channel_monitor_checker_body_test.go b/backend/internal/service/channel_monitor_checker_body_test.go index 2357646337..922eb86732 100644 --- a/backend/internal/service/channel_monitor_checker_body_test.go +++ b/backend/internal/service/channel_monitor_checker_body_test.go @@ -498,3 +498,26 @@ func TestValidateChallenge_AnthropicTextAfterThinking(t *testing.T) { t.Fatalf("validateChallenge(%q, %q) = false, want true", respText, "2") } } + +func TestGeminiMonitorBodyIncludesExplicitUserRole(t *testing.T) { + adapter := providerAdapters[MonitorProviderGemini] + body, err := adapter.buildBody("gemini-3.6-flash", "Reply with only 7.") + if err != nil { + t.Fatalf("buildBody() error = %v", err) + } + + var payload struct { + Contents []struct { + Role string `json:"role"` + } `json:"contents"` + } + if err := json.Unmarshal(body, &payload); err != nil { + t.Fatalf("Unmarshal() error = %v", err) + } + if len(payload.Contents) != 1 { + t.Fatalf("contents length = %d, want 1", len(payload.Contents)) + } + if payload.Contents[0].Role != "user" { + t.Fatalf("contents[0].role = %q, want user", payload.Contents[0].Role) + } +}