GoogleGemini

Google Gemini LLM Integration for AI-powered analysis and chat capabilities. This integration provides access to Google Gemini's large language models for: - AI-powered chat conversations - Text analysis and generation - Natural language processing tasks Supports both Google AI Studio (API key) and Google Cloud Vertex AI (service account) authentication. Supported models include Gemini 2.0 Flash, Gemini 1.5 Pro, and various preview models.

Cloud Services · Google Gemini

Details

IDGoogleGemini
ProviderGoogle
CategoryCloud Services
From Version6.10.0
Docker Imagedemisto/google-api-py3:1.0.0.10182333
Supported ModulesXSIAM Agentix

README

Google Gemini Integration

This integration provides access to Google Gemini’s large language models for AI-powered analysis and chat capabilities in Cortex XSOAR or XSIAM. Supports both Google AI Studio (API key) and Google Cloud Vertex AI (service account) authentication.

Configure GoogleGemini in Cortex XSOAR

  1. Navigate to Settings > Integrations > Servers & Services.
  2. Search for Google Gemini.
  3. Click Add instance to create and configure a new integration instance.

Configure GoogleGemini in Cortex XSIAM

  1. Go to Marketplace
  2. Search for GoogleGemini
  3. Add ContentPack
  4. Search for GoogleGemini in Data Source and Integrations
  5. Create new instance

Instance Configuration Parameters

Parameter Description Required
Authentication Type Choose between “AI Studio API Key” or “Vertex AI Service Account” True
Server URL For AI Studio: https://generativelanguage.googleapis.com. For Vertex AI: https://aiplatform.googleapis.com (auto-detected if unchanged). True
API Key Google AI Studio API key. Required when using AI Studio. False
Service Account Key (JSON) Service Account Key JSON for Vertex AI authentication. Required when using Vertex AI. False
Project ID Google Cloud Project ID. Required when using Vertex AI. False
Location Google Cloud location for Vertex AI (e.g., global, us-central1). Defaults to global. False
Default Model Select a Gemini model from the dropdown True
Max tokens Maximum number of tokens in the response (default: 1024) True
Temperature Controls randomness in responses (0.0-2.0) False
Top P Nucleus sampling parameter (0.0-1.0) False
Top K Top-k sampling parameter False
Trust any certificate (not secure) Whether to ignore SSL certificate verification False
Use system proxy settings Whether to use system proxy configuration False

Supported Models

The integration supports various Gemini models including:

Stable Models:

  • gemini-2.5-pro
  • gemini-2.5-flash

Deprecated (Legacy Only) Models — operational until June 1, 2026:

  • gemini-2.0-flash
  • gemini-2.0-flash-lite

Preview Models:

  • gemini-3.1-pro-preview
  • gemini-3.1-flash-preview
  • gemini-3.1-flash-lite

Note: You can also use the freetext model field to specify newer models not in the dropdown list.

Commands

You can execute these commands from the CLI, as part of an automation, or in a playbook.
After you successfully execute a command, a DBot message appears in the War Room with the command details.

google-gemini-send-message


Send a prompt to Google Gemini and receive an AI-generated response.

Base Command

google-gemini-send-message

Input

Argument Name Description Required
prompt The prompt or question to send to the AI model Required
model Override the instance default model for this specific request Optional
history Conversation history in JSON format for maintaining context across multiple interactions Optional
save_conversation Whether to automatically save and retrieve conversation history (default: false) Optional

Context Output

Path Type Description
GoogleGemini.Chat.Prompt String The original prompt sent to the model
GoogleGemini.Chat.Response String The AI model’s response
GoogleGemini.Chat.Model String The model used for generation
GoogleGemini.Chat.Temperature Number The temperature parameter used for response generation
GoogleGemini.Chat.History Array Complete conversation history (when save_conversation=true)
GoogleGemini.Chat.ConversationId String A unique identifier, used to identify the chat session

Command Examples

!google-gemini-send-message prompt="What is artificial intelligence?"

!google-gemini-send-message prompt="Analyze this suspicious email for potential threats" model="gemini-2.5-pro"

!google-gemini-send-message prompt="Continue our previous discussion" history='[{"role": "user", "parts": [{"text": "Hello"}]}, {"role": "model", "parts": [{"text": "Hi there! How can I help you?"}]}]'

!google-gemini-send-message prompt="What are the next investigation steps?" save_conversation=true

Conversation History Management

When save_conversation=true, the integration:

  • Automatically retrieves existing conversation history from context
  • Uses the last exchange (user + model response) to provide context for the current request
  • Saves the complete updated conversation history to GoogleGemini.Chat.History
  • Allows analysts to maintain conversation continuity without manually managing JSON history

Human Readable Output

The command returns the AI model’s response as human-readable output in the War Room.

Setup Instructions

AI Studio (API Key)

  1. Obtain API Key: Visit Google AI Studio to create an API key.
  2. Configure Integration: Add a new GoogleGemini integration instance, set Authentication Type to AI Studio API Key, and enter your API key.
  3. Test Connection: Use the Test button to verify connectivity.
  4. Start Using: Execute the google-gemini-send-message command for AI interactions.

Vertex AI (Service Account)

  1. Create a Service Account: In the Google Cloud Console, go to IAM & Admin > Service Accounts and create a service account with the Vertex AI User role.
  2. Generate a JSON Key: On the service account page, create a new JSON key and download it.
  3. Configure Integration: Add a new GoogleGemini integration instance, set Authentication Type to Vertex AI Service Account, and paste the full JSON key contents into the Service Account Key field.
  4. Set Project ID: Enter your Google Cloud Project ID.
  5. Set Location: Enter the location (default: global). Use us-central1, europe-west4, etc. for regional endpoints.
  6. Test Connection: Use the Test button to verify connectivity.

Troubleshooting and Tips

  • Ensure your API key has access to the Generative Language API.
  • Verify your Cortex XSOAR or XSIAM instance can access the configured endpoint.
  • Check that the specified model is available in your region.
  • Review usage quotas and rate limits for your API key or project.
  • The integration attempts to use models not included in the official list and issues a warning.
  • Ensure the service account has the roles/aiplatform.user role and the Vertex AI API is enabled in your project.
  • For AI Studio, use the server URL https://generativelanguage.googleapis.com. For Vertex AI, the URL auto-switches to https://aiplatform.googleapis.com by default.

Configuration parameters

  • auth_type — Authentication Type (required)
  • url — Server URL (required)
  • api_key
  • service_account_key
  • project_id — Project ID
  • location — Location
  • model — Default Model (required)
  • max_tokens — Max tokens (required)
  • temperature — Temperature
  • top_p — Top P
  • top_k — Top K
  • insecure — Trust any certificate (not secure)
  • proxy — Use system proxy settings

Commands (1)

  • google-gemini-send-message

    Send a chat message to the Gemini AI model.

"""Integration for Google Gemini AI Assistant.

This integration provides AI-powered analysis and chat capabilities for XSOAR users.
Supports both Google AI Studio (API key) and Vertex AI (service account) authentication.
"""

import demistomock as demisto
from CommonServerPython import *  # noqa # pylint: disable=unused-wildcard-import
from CommonServerUserPython import *  # noqa

""" IMPORTS """
import json
from typing import Any
from uuid import uuid4

from google.oauth2 import service_account
from google.auth.transport.requests import Request

""" CONSTANTS """
DATE_FORMAT = "%Y-%m-%dT%H:%M:%SZ"  # ISO8601
SUPPORTED_MODELS = [
    # Stable models
    "gemini-2.5-pro",
    "gemini-2.5-flash",
    # Deprecated (Legacy Only) - operational until June 1, 2026
    "gemini-2.0-flash",
    "gemini-2.0-flash-lite",
    # Preview models
    "gemini-3.1-pro-preview",
    "gemini-3.1-flash-preview",
    "gemini-3.1-flash-lite",
]
AUTH_TYPE_AI_STUDIO = "AI Studio API Key"
AUTH_TYPE_VERTEX_AI = "Vertex AI Service Account"
VERTEX_AI_BASE_URL = "https://aiplatform.googleapis.com"
GOOGLE_AUTH_SCOPE = "https://www.googleapis.com/auth/cloud-platform"


class Client(BaseClient):
    """Client to interact with the Google Gemini API.

    Supports both AI Studio (API key) and Vertex AI (service account) authentication.
    It inherits from BaseClient which handles proxy, SSL verification, etc.
    """

    def __init__(
        self,
        base_url: str,
        verify: bool,
        proxy: bool,
        auth_type: str,
        model: str = "gemini-2.5-flash",
        max_tokens: int = 1024,
        temperature: float | None = None,
        top_p: float | None = None,
        top_k: int | None = None,
        api_key: str | None = None,
        service_account_json: str | None = None,
        project_id: str | None = None,
        location: str = "global",
    ):
        """Initialize Client class.

        :param base_url: The base URL of the API.
        :param verify: Whether to verify SSL certificate.
        :param proxy: Whether to use system proxy settings.
        :param auth_type: Authentication type - AI Studio API Key or Vertex AI Service Account.
        :param model: The default Gemini model to use for requests.
        :param max_tokens: Default maximum tokens for responses.
        :param temperature: Default temperature for response generation.
        :param top_p: Default top-p value for response generation.
        :param top_k: Default top-k value for response generation.
        :param api_key: API key for AI Studio authentication.
        :param service_account_json: Service account JSON key for Vertex AI authentication.
        :param project_id: Google Cloud project ID for Vertex AI.
        :param location: Google Cloud location for Vertex AI (default: global).
        """
        super().__init__(base_url=base_url, verify=verify, proxy=proxy)
        self.auth_type = auth_type
        self.model = model
        self.max_tokens = max_tokens
        self.temperature = temperature
        self.top_p = top_p
        self.top_k = top_k

        if auth_type == AUTH_TYPE_AI_STUDIO:
            self.api_key = api_key
            self._headers = {
                "Content-Type": "application/json",
                "Accept": "application/json",
                "x-goog-api-key": self.api_key,
            }
        else:
            try:
                self.service_account_info: dict[str, Any] = json.loads(service_account_json) if service_account_json else {}
            except json.JSONDecodeError as e:
                raise ValueError(f"Invalid Service Account JSON provided: {e}")
            self.project_id = project_id
            self.location = location or "global"
            self._credentials = service_account.Credentials.from_service_account_info(
                self.service_account_info,
                scopes=[GOOGLE_AUTH_SCOPE],
            )
            self._headers = {
                "Content-Type": "application/json",
                "Accept": "application/json",
            }

    def _get_access_token(self) -> str:
        """Get a valid access token for Vertex AI using google-auth credentials.

        Refreshes the token automatically when expired.

        :return: Valid OAuth2 access token string.
        """
        if not self._credentials.valid:
            demisto.debug("Refreshing Vertex AI access token")
            self._credentials.refresh(Request())
        return self._credentials.token

    def _get_request_headers(self) -> dict[str, str] | None:
        """Get the appropriate request headers based on auth type.

        For AI Studio, returns None to use the default self._headers (with API key).
        For Vertex AI, returns headers with a fresh Bearer token.

        :return: Headers dict for Vertex AI, or None for AI Studio.
        """
        if self.auth_type == AUTH_TYPE_AI_STUDIO:
            return None
        access_token = self._get_access_token()
        return {
            "Content-Type": "application/json",
            "Accept": "application/json",
            "Authorization": f"Bearer {access_token}",
        }

    def _get_url_suffix(self, model: str) -> str:
        """Get the appropriate URL suffix based on auth type and model.

        :param model: The model name to use.
        :return: URL suffix string for the generateContent endpoint.
        """
        if self.auth_type == AUTH_TYPE_AI_STUDIO:
            return f"/v1beta/models/{model}:generateContent"
        return f"/v1/projects/{self.project_id}/locations/{self.location}/publishers/google/models/{model}:generateContent"

    def send_chat_message(
        self,
        prompt: str,
        model: str | None = None,
        history: list[dict[str, Any]] | None = None,
    ) -> dict[str, Any]:
        """Send a chat message to the Gemini API with optional conversation history.

        Conversation history format:
        [
            {
                "role": "user",
                "parts": [{"text": "Previous user message"}]
            },
            {
                "role": "model",
                "parts": [{"text": "Previous AI response"}]
            }
        ]
        :param prompt: The user's prompt/question.
        :param model: The Gemini model to use (defaults to instance default).
        :param history: Optional conversation history in Gemini format.
        :return: Dictionary containing the API response.
        """
        selected_model = model or self.model
        contents = []

        if history:
            contents.extend(history)

        # Add current user prompt
        contents.append({"role": "user", "parts": [{"text": prompt}]})

        # Build generation config using instance defaults
        generation_config = assign_params(
            maxOutputTokens=self.max_tokens, temperature=self.temperature, topP=self.top_p, topK=self.top_k
        )

        request_body = {"contents": contents, "generationConfig": generation_config}

        return self._http_request(
            method="POST",
            url_suffix=self._get_url_suffix(selected_model),
            json_data=request_body,
            headers=self._get_request_headers(),
        )


def test_module(client: Client):
    """Tests API connectivity and authentication.

    Uses a simple chat message to verify that the API is reachable and the provided token is valid.

    :param client: Google Gemini API client.
    :return: 'ok' if successful, or an error message string.
    """
    try:
        client.send_chat_message("Hello, please respond with 'OK' to test connectivity.")
        return "ok"
    except DemistoException as e:
        err_msg = e.message
        try:
            err_msg = demisto.get(e.res.json(), "error.message", err_msg)
        except Exception:
            pass
        return_error(f"An unexpected error occurred during connectivity test: {err_msg}")


def google_gemini_send_message_command(client: Client, args: dict[str, Any]):
    """Command function to send a chat message to the Google Gemini API with optional conversation history.

    :param client: Google Gemini API client.
    :param args: Dictionary of command arguments (prompt, model, history, save_conversation).
    :return: CommandResults object(s) with outputs and readable representation.
    """
    prompt = str(args.get("prompt", ""))
    model = args.get("model", None)
    history_arg = args.get("history", [])
    save_conversation = argToBoolean(args.get("save_conversation", False))

    if not prompt:
        raise ValueError("The 'prompt' argument is required.")

    history = []
    if history_arg:
        try:
            if isinstance(history_arg, str):
                history = json.loads(history_arg)
            elif isinstance(history_arg, list):
                history = history_arg
        except json.JSONDecodeError:
            raise ValueError("History must be valid JSON array of conversation objects.")

    conversation_id = None
    outputs_key_field = "prompt"
    if save_conversation:
        context = demisto.context()
        existing_history = None

        if google_gemini_context := demisto.get(context, "GoogleGemini.Chat"):
            if isinstance(google_gemini_context, dict) and "History" in google_gemini_context:
                existing_history = google_gemini_context["History"]
                conversation_id = google_gemini_context["ConversationId"]

            elif isinstance(google_gemini_context, list):
                for item in reversed(google_gemini_context):
                    if isinstance(item, dict) and "History" in item:
                        existing_history = item["History"]
                        conversation_id = item["ConversationId"]
                        break

        # trying to take the last 2 entries
        if existing_history and isinstance(existing_history, list):
            if len(existing_history) >= 2:
                history = existing_history[-2:]
            else:
                history = existing_history

    response = client.send_chat_message(prompt, model, history)

    content = ""
    finish_reason = ""
    if (candidates := response.get("candidates")) and len(candidates) > 0:
        parts = demisto.get(candidates[0], "content.parts")
        if parts and isinstance(parts, list) and len(parts) > 0 and isinstance(parts[0], dict):
            content = parts[0].get("text")  # type: ignore[assignment]
        else:
            finish_reason = demisto.get(candidates[0], "finishReason")

    if not content:
        content = "No response generated."
        if finish_reason:
            return_warning(f"The model finished before completing the full response, due to {finish_reason}")

    outputs = {"Prompt": prompt, "Response": content, "Model": model or client.model, "Temperature": client.temperature}
    if save_conversation:
        current_conversation = history.copy() if history else []
        current_conversation.append({"role": "user", "parts": [{"text": prompt}]})

        if content and content != "No response generated.":
            current_conversation.append({"role": "model", "parts": [{"text": content}]})

        outputs["History"] = current_conversation
        outputs["ConversationId"] = conversation_id or str(uuid4())
        outputs_key_field = "ConversationId"

    return CommandResults(
        outputs_prefix="GoogleGemini.Chat",
        outputs_key_field=outputs_key_field,
        outputs=outputs,
        raw_response=response,
        readable_output=content,
    )


def main():
    """Main execution function for the integration.

    Parses integration parameters and command arguments, initializes the client,
    and calls the appropriate command function.
    """
    params = demisto.params()
    auth_type = params.get("auth_type", AUTH_TYPE_AI_STUDIO)
    verify_certificate = not argToBoolean(params.get("insecure", False))
    proxy = argToBoolean(params.get("proxy", False))
    model = params.get("model", ["gemini-2.5-flash"])  # use multi select to enable adding custom val
    max_tokens = arg_to_number(params.get("max_tokens", 1024)) or 1024

    # Handle optional parameters - use defaults if empty or not provided
    temperature = arg_to_number(params.get("temperature", "").strip())
    top_p = arg_to_number(params.get("top_p", "").strip())
    top_k = arg_to_number(params.get("top_k", "").strip())

    # Auth-specific parameters
    api_key: str | None = None
    service_account_json: str | None = None
    project_id: str | None = None
    location: str = "global"

    if auth_type == AUTH_TYPE_VERTEX_AI:
        base_url = params.get("url", VERTEX_AI_BASE_URL)
        # Auto-switch from AI Studio default URL to Vertex AI URL
        if base_url == "https://generativelanguage.googleapis.com":
            base_url = VERTEX_AI_BASE_URL
        service_account_json = params.get("service_account_key", {}).get("password")
        project_id = params.get("project_id")
        location = params.get("location", "global") or "global"
        if not service_account_json:
            return_error("Service Account Key JSON is required for Vertex AI authentication.")
            return
        if not project_id:
            return_error("Project ID is required for Vertex AI authentication.")
            return
    else:
        base_url = params.get("url", "https://generativelanguage.googleapis.com")
        api_key = params.get("api_key", {}).get("password")
        if not api_key:
            return_error("API key is not configured. Please configure it in the instance settings.")
            return

    command = demisto.command()
    demisto.debug(f"Command being called is {command}")

    try:
        if len(model) > 1:
            raise DemistoException("Please select one model only.")
        client = Client(
            base_url=base_url,
            verify=verify_certificate,
            proxy=proxy,
            auth_type=auth_type,
            model=model[0],
            max_tokens=max_tokens,
            temperature=temperature,
            top_p=top_p,
            top_k=top_k,
            api_key=api_key,
            service_account_json=service_account_json,
            project_id=project_id,
            location=location,
        )
        args = demisto.args()

        if command == "test-module":
            result = test_module(client)
        elif command == "google-gemini-send-message":
            result = google_gemini_send_message_command(client, args)
        else:
            raise NotImplementedError(f"Command {command} is not implemented")

        return_results(result)

    except Exception as e:
        return_error(f"Failed to execute {command} command.\nError:\n{str(e)}")


if __name__ in ("__main__", "__builtin__", "builtins"):  # pragma: no cover
    main()