Packages
nous
0.12.2
0.17.0
0.16.6
0.16.5
0.16.4
0.16.3
0.16.2
0.16.1
0.16.0
0.15.8
0.15.7
0.15.6
0.15.5
0.15.4
0.15.3
0.15.2
0.15.1
0.15.0
0.14.3
0.14.2
0.14.1
0.14.0
0.13.3
0.13.2
0.13.1
0.13.0
0.12.17
0.12.16
0.12.15
0.12.14
0.12.13
0.12.12
0.12.11
0.12.9
0.12.7
0.12.6
0.12.5
0.12.3
0.12.2
0.12.0
0.11.3
0.11.0
0.10.1
0.10.0
0.9.0
0.8.1
0.8.0
0.7.2
0.7.1
0.7.0
0.5.0
AI agent framework for Elixir with multi-provider LLM support
Current section
Files
Jump to
Current section
Files
lib/nous/providers/gemini.ex
defmodule Nous.Providers.Gemini do
@moduledoc """
Google Gemini provider implementation.
Supports Gemini models via the Google AI Generative Language API.
## Usage
# Basic usage
{:ok, response} = Nous.Providers.Gemini.chat(%{
model: "gemini-2.0-flash-exp",
contents: [%{"role" => "user", "parts" => [%{"text" => "Hello"}]}]
})
# With system instruction
{:ok, response} = Nous.Providers.Gemini.chat(%{
model: "gemini-2.0-flash-exp",
systemInstruction: %{"parts" => [%{"text" => "You are helpful."}]},
contents: [%{"role" => "user", "parts" => [%{"text" => "Hello"}]}],
generationConfig: %{"temperature" => 0.7, "maxOutputTokens" => 1024}
})
# Streaming
{:ok, stream} = Nous.Providers.Gemini.chat_stream(params)
Enum.each(stream, fn event -> IO.inspect(event) end)
## Configuration
# In config.exs
config :nous, :gemini,
api_key: "AIza...",
base_url: "https://generativelanguage.googleapis.com/v1beta" # optional
## Note on Authentication
Unlike OpenAI/Anthropic which use headers, Gemini uses query parameter auth:
`?key=API_KEY`
"""
use Nous.Provider,
id: :gemini,
default_base_url: "https://generativelanguage.googleapis.com/v1beta",
default_env_key: "GOOGLE_AI_API_KEY"
alias Nous.Providers.HTTP
@default_timeout 60_000
@streaming_timeout 120_000
# Override to convert from generic format to Gemini's format
defp build_request_params(model, messages, settings) do
merged_settings = Map.merge(model.default_settings, settings)
# Convert messages to Gemini format: {system_prompt, contents}
{system_prompt, contents} = Nous.Messages.to_provider_format(messages, :gemini)
params = %{"model" => model.model, "contents" => contents}
params =
if system_prompt do
Map.put(params, "systemInstruction", %{"parts" => [%{"text" => system_prompt}]})
else
params
end
# Map generic settings to Gemini's generationConfig
generation_config =
%{}
|> maybe_put("temperature", merged_settings[:temperature])
|> maybe_put("maxOutputTokens", merged_settings[:max_tokens])
|> maybe_put("topP", merged_settings[:top_p])
|> maybe_put("stopSequences", merged_settings[:stop_sequences] || merged_settings[:stop])
# Merge any explicit generationConfig from settings
generation_config =
Map.merge(generation_config, merged_settings[:generationConfig] || %{})
if map_size(generation_config) > 0 do
Map.put(params, "generationConfig", generation_config)
else
params
end
end
@impl Nous.Provider
def chat(params, opts \\ []) do
model = Map.get(params, "model") || Map.get(params, :model) || "gemini-2.0-flash-exp"
api_key = api_key(opts)
url = build_url(base_url(opts), model, api_key, :generate)
headers = build_headers()
timeout = Keyword.get(opts, :timeout, @default_timeout)
# Remove model from params (it's in the URL)
body = params |> Map.delete("model") |> Map.delete(:model)
HTTP.post(url, body, headers, timeout: timeout)
end
@impl Nous.Provider
def chat_stream(params, opts \\ []) do
model = Map.get(params, "model") || Map.get(params, :model) || "gemini-2.0-flash-exp"
api_key = api_key(opts)
url = build_url(base_url(opts), model, api_key, :stream)
headers = build_headers()
timeout = Keyword.get(opts, :timeout, @streaming_timeout)
finch_name = Keyword.get(opts, :finch_name, Nous.Finch)
# Remove model from params (it's in the URL)
body = params |> Map.delete("model") |> Map.delete(:model)
HTTP.stream(url, body, headers, timeout: timeout, finch_name: finch_name)
end
# Build URL with model and API key in query params
defp build_url(base_url, model, api_key, :generate) do
"#{base_url}/models/#{model}:generateContent?key=#{api_key}"
end
defp build_url(base_url, model, api_key, :stream) do
"#{base_url}/models/#{model}:streamGenerateContent?key=#{api_key}"
end
# Build headers (no auth header - it's in the URL)
defp build_headers do
[{"content-type", "application/json"}]
end
end