Google Gemini
BeamWeaver uses the Gemini Developer API for chat, thinking, supported hosted tools, media input, token counting and cached-content references. Vertex AI routing and media-generation models are separate APIs outside this adapter.
Setup and first request
import Config
config :beam_weaver, :google, api_key: System.fetch_env!("GOOGLE_API_KEY")
Save configuration in your application runtime file, then make a real request:
alias BeamWeaver.Core.{ChatModel, Message}
{:ok, model} = BeamWeaver.Models.init_chat_model("google:gemini-3.5-flash", max_output_tokens: 1_024, timeout: 60_000)
{:ok, reply} = ChatModel.invoke(model, "Explain parcel tracking in one sentence.")
true = byte_size(Message.text(reply)) > 0
true = reply.usage_metadata.total_tokens > 0
Use the same identifier in an agent declaration. Gemini IDs require google:. Keep complete messages when continuing function calls; native parts can carry provider state beyond display text.
Gemini 4 Argon
Use google:gemini-4-argon with thinking_level: :low, :medium (the provider default), or :high. Its 1,048,576-token window is shared by input, thinking and output. BeamWeaver follows continuation checkpoints automatically for ordinary invocations, collected responses, and text/typed streams. You receive one combined reply with all content, thought signatures, tool calls, and usage. The default output budget is 65,536 tokens; set max_output_tokens: higher for longer work, up to the shared context limit minus your input. MAX_TOKENS stops generation: BeamWeaver never raises the budget you selected.
Argon uses implicit caching only. cached_content: and sampling controls are rejected by its strict profile. Current input/cached-input/output rates are $2/$0.10/$10 per million tokens through November 30, 2026, then $4/$0.20/$20. Use UsageCost.calculate/3 with at: for a dated estimate. See Google's
model specification
and
pricing
.
The client uses streaming HTTP internally, even when the caller wants one final reply; Argon model constructors default to a 20-minute timeout per request. It preserves the original request across hops and sums their billed usage. usage_metadata.initial_input_tokens is the original prompt size; context_tokens is that size plus all generated thinking/output. Summarization uses context size instead of cumulative billed tokens, which include repeated inputs.
For reliable streaming, chunks are delivered when a checkpoint commits them or the stream finishes successfully. This can delay visible output until a checkpoint or completion. A dropped stream resumes at its latest checkpoint, discarding uncommitted chunks so text is not duplicated. Before any checkpoint, it retries the original request. max_continuation_retries: defaults to 2 per unfinished hop; permanent errors fail immediately. Halting enumeration cancels the active request and prevents further hops.
Checkpoint tokens can make the wire response much larger than the visible answer. Automatic continuation uses the stream byte limit (64 MiB by default) for each HTTP response, rather than the ordinary transport's 5 MB limit. Explicit max_response_bytes: limits still apply.
Set automatic_continuation: false on the model or invocation for manual control. Then a CONTINUATION response is returned as provider_pause, and its response_metadata.continuation_token can be passed as continuation_token: with the original messages and generation options. Manual REST calls retain the 32,768 non-streaming / 65,536 streaming per-request defaults. See Google's
long-decode guide
.
Options and thinking
| Option | Purpose |
|---|---|
max_output_tokens: / max_tokens:
| Output budget |
thinking_level:
| Supported level for the chosen model |
thinking_budget:
| Token budget only where supported |
include_thoughts:
| Request returned thought summaries |
cached_content:
| Actual cached-content resource name |
safety_settings:
| Native category thresholds |
stop_sequences: / stop:
| Stop text |
labels:
| Labels sent at the top level of the request |
generation_config:
| Additional native generation controls |
base_url:
| Developer API root |
Newer Flash profiles restrict sampling and use thinking levels rather than budgets. Validate the exact model's options instead of assuming all Gemini versions accept the same controls. Message.text/1 excludes reasoning blocks; usage can report reasoning tokens separately.
Thinking controls are model-specific. This complete agent requests thoughts and invokes the configured model:
defmodule MyApp.SupportAgent do
use BeamWeaver.Agent
model "google:gemini-3.8-flash", thinking_level: :high, include_thoughts: true, timeout: 120_000
system_prompt "You are Acme's support agent."
end
{:ok, result} = MyApp.SupportAgent.invoke(%{messages: ["Reply with the word ready."]})
true = byte_size(result.messages |> List.last() |> BeamWeaver.Core.Message.text()) > 0
Built-in tools
Google runs supported search/code tools on its servers. This call checks actual grounding metadata from search:
{:ok, searched} =
ChatModel.invoke(
model,
"Use Google Search to find the official Elixir programming language website and cite it.",
tools: [BeamWeaver.Google.Tools.google_search()]
)
true = byte_size(Message.text(searched)) > 0
true = is_map(searched.response_metadata.grounding_metadata)
true = map_size(searched.response_metadata.grounding_metadata) > 0
Other helpers include URL context, Maps, code execution, file search and MCP servers. File search needs actual store resources. A computer-use declaration requires your application's browser/desktop executor and returned action results; BeamWeaver does not supply that executor.
Hosted tools belong in model call options. Ordinary agent tools use the Tool DSL . Supported image/PDF tool results are carried in Gemini function-response parts.
Context caching
Automatic prefix caching reports usage when a hit occurs. Explicit caching requires a resource created through Google's API. From a configured checkout, this creates a short-lived resource, uses it and deletes it:
root = "https://generativelanguage.googleapis.com/v1beta"
headers = [{"x-goog-api-key", System.fetch_env!("GOOGLE_API_KEY")}]
policy = String.duplicate("Returns are accepted within 30 days. Opened items must include all parts.\n", 400)
created =
Req.post!(root <> "/cachedContents",
headers: headers,
json: %{model: "models/gemini-3.5-flash", ttl: "300s", contents: [%{role: "user", parts: [%{text: policy}]}]},
retry: false,
receive_timeout: 60_000
)
true = created.status in 200..299
name = Map.fetch!(created.body, "name")
try do
{:ok, cached} =
BeamWeaver.Models.init_chat_model("google:gemini-3.5-flash",
cached_content: name,
max_tokens: 1_024,
timeout: 60_000
)
{:ok, reply} = ChatModel.invoke(cached, "How many days do I have to return an item?")
true = Message.text(reply) =~ "30"
true = get_in(reply.usage_metadata, [:input_token_details, :cache_read]) > 0
after
deleted = Req.delete!(root <> "/" <> name, headers: headers, retry: false)
true = deleted.status in 200..299
end
The application owns resource creation/expiry/deletion; the model option only references it. prompt_caching adds no marker for Gemini. See the official
caching API
for resource constraints.
Media and token counting
Gemini profiles support text, image, PDF, audio and video inputs. Use actual supported media bytes or resources, not fabricated IDs. Messages explains content blocks; the model's profile validates capability compatibility.
{:ok, tokens} = BeamWeaver.Google.ChatModel.count_tokens(model, "Check order A-1001.")
true = is_integer(tokens) and tokens > 0
Counting sends the same input, system instructions, tools, cached-content reference and generation options as generation, wrapped in generateContentRequest when needed.
Counting calls the provider but does not generate an answer. Safety filtering can affect completion even on HTTP success; inspect the provider outcome and terminal stream events.
Models
Limits are local profile data. A dash means not applicable or not recorded, not an unlimited allowance.
| Model | Input / output tokens | Operations and capabilities |
|---|---|---|
google:gemini-3.1-flash-lite
| 1,048,576 / 65,536 | chat; text, image, PDF, audio, video; tools; structured output; reasoning |
google:gemini-3.1-pro-preview
| 1,048,576 / 65,536 | chat; text, image, PDF, audio, video; tools; structured output; reasoning |
google:gemini-3.5-flash
| 1,048,576 / 65,536 | chat; text, image, PDF, audio, video; tools; structured output; reasoning |
google:gemini-3.5-flash-lite
| 1,048,576 / 65,536 | chat; text, image, PDF, audio, video; tools; structured output; reasoning |
google:gemini-3.6-flash
| 1,048,576 / 65,536 | chat; text, image, PDF, audio, video; tools; structured output; reasoning |
google:gemini-3.7-flash
| 1,048,576 / 65,536 | chat; text, image, PDF, audio, video; tools; structured output; reasoning |
google:gemini-3.8-flash
| 1,048,576 / 65,536 | chat; text, image, PDF, audio, video; tools; structured output; reasoning |
google:gemini-4-argon
| 1,048,576 / 1,048,576 | chat; text, image, PDF, audio, video; tools; structured output; reasoning |
Gemini 3.5 Flash is served by 3.6 Flash, and 3.7 Flash by 3.8 Flash; their profiles use the serving models' capabilities and rates. Preview identifiers and aliases can have different availability from stable models. See Google's model reference and retirement schedule .
Further reading
Testing covers deterministic application tests and replay. Live requests above check the configured Google integration.