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) + } +}