Invokes Google Gemini models for structured outputs, multi-modal tasks, and Google-specific features...
Delegate tasks to Google's Gemini models when they offer advantages over Claude.
Image generation:
Speech (TTS):
Structured outputs:
Cost optimization:
Multi-modal tasks:
uv pip install requests pydantic
Credentials โ Option A (recommended): Cloudflare AI Gateway
Source /mnt/project/proxy.env with CF_ACCOUNT_ID, CF_GATEWAY_ID, CF_API_TOKEN.
Requests route through Cloudflare AI Gateway, bypassing IP blocks. Google API key stored in gateway via BYOK.
Credentials โ Option B: Direct Google API
If no proxy.env, falls back to direct: GOOGLE_API_KEY.txt or API_CREDENTIALS.json.
Generate images using Gemini's native image models. This is the primary way to create illustrations, blog headers, diagrams, and visual content.
import sys
sys.path.append('/mnt/skills/user/invoking-gemini/scripts')
from gemini_client import generate_image
# One call โ returns {"path": "...", "caption": "..."} or None
result = generate_image("A watercolor painting of a mountain lake at sunset")
print(result["path"]) # /mnt/user-data/outputs/gemini_image_1740000000.png
generate_image(
prompt: str, # The image description
output_path: str = None, # Auto-generates if omitted
model: str = "nano-banana-2", # Default: fast. Use "image-pro" for quality
temperature: float = 0.7, # 0.5-0.7 for diagrams, 0.7-0.8 for illustrations
) -> dict | None
# Returns: {"path": "/mnt/user-data/outputs/gemini_image_*.png", "caption": str|None}
# Returns None on failure
| Alias | Model | Best For | Cost/image |
|---|---|---|---|
"nano-banana-2" or "image" |
gemini-3.1-flash-image-preview | Fast iteration, drafts | $0.067 |
"image-pro" or "nano-banana-pro" |
gemini-3-pro-image-preview | Published content, text rendering | $0.134 |
import sys
sys.path.append('/mnt/skills/user/invoking-gemini/scripts')
from gemini_client import generate_image
# 1. Compose prompt with style prefix + subject
style_prefix = (
"Style: Risograph-inspired editorial illustration. "
"Visible halftone dot texture and slight color misregistration between layers. "
"Limited ink palette: deep indigo, warm coral, and sage green on off-white paper. "
"Layered transparency where colors overlap creates rich secondary tones. "
"Modern and professional โ the aesthetic of an indie design studio, not a fantasy novel. "
"Generous whitespace. No photorealism, no glow effects, no cyberpunk. No text or labels."
)
subject = "A raven perched on a stack of books, observing a network graph"
prompt = f"{style_prefix}\n\nSubject: {subject}. Wide landscape format, suitable as a blog header."
# 2. Generate (use image-pro for published content)
result = generate_image(prompt, model="image-pro", temperature=0.75)
if result:
print(f"Saved: {result['path']}")
# 3. Present to user
# present_files([result["path"]])
result = generate_image(
"A logo for a coffee shop called 'Bean There'",
output_path="/mnt/user-data/outputs/coffee_logo.png"
)
Gemini 3.8 Flash TTS and Flash-Lite TTS went GA on 2026-09-23. Output is WAV, 24 kHz mono 16-bit, SynthID-watermarked.
from gemini_client import generate_speech, design_voice, list_voices
r = generate_speech("Odin kept two ravens. <short pause> Huginn was thought.",
output_path="/tmp/line.wav", voice="Algenib",
style="quiet and dry, unhurried")
# {'path': '/tmp/line.wav', 'seconds': 4.2, 'audio_tokens': 135} or None
v = design_voice("A low, dry, quietly amused male voice with a faint rasp. "
"Soft southern British accent.", "narrator", gender="male",
language_code="en-GB") # {'id': 'voice_...', 'sample_path': ...}
generate_speech("...", voice=v["id"])
lows = list_voices(gender="male", pitch="low") # library of 2,089 prebuilt voices
Charon, Kore, Algenib "gravelly",
Enceladus "breathy", ...) plus 2,059 persona voices with ids like
en-gb-storyteller-4. list_voices() returns accent, pitch, gender and a
description for each; the accent filter needs the exact string ("Winchester
English"), so filter accents on the returned field.style= (a speech_metadata annotation). Do not prefix the
text with "Style: ..." โ the 3.8 models read the prefix aloud, and
systemInstruction is rejected. Inline events go in the text: <laugh>,
<sigh>, <breath>, <short pause>; CAPITALS stress a word.medium.en) and a retake.import sys
sys.path.append('/mnt/skills/user/invoking-gemini/scripts')
from gemini_client import invoke_gemini
response = invoke_gemini(
prompt="Explain quantum computing in 3 bullet points",
model="flash", # gemini-3.8-flash (default)
)
print(response)
Use Pydantic models for guaranteed JSON Schema compliance:
from gemini_client import invoke_with_structured_output
from pydantic import BaseModel, Field
class BookAnalysis(BaseModel):
title: str
genre: str = Field(description="Primary genre")
key_themes: list[str] = Field(max_length=5)
rating: int = Field(ge=1, le=5)
result = invoke_with_structured_output(
prompt="Analyze the book '1984' by George Orwell",
pydantic_model=BookAnalysis
)
print(result.title) # "1984"
Nested models are supported. Gemini's responseSchema rejects $ref/$defs,
which pydantic emits for every nested model, so the client inlines them before
sending:
class Finding(BaseModel):
claim: str
confidence: Literal["high", "medium", "low"]
note: str | None = None
class Analysis(BaseModel):
findings: list[Finding] # nested โ inlined for you
gaps: list[str]
Budget output generously. Thinking tokens count against max_output_tokens
(default 32768). Too low and the JSON truncates mid-object, which surfaces as a
pydantic parse error rather than a length error โ the client now detects
finishReason=MAX_TOKENS and says so explicitly.
from gemini_client import invoke_parallel
results = invoke_parallel(
prompts=["Summarize Hamlet", "Summarize Macbeth", "Summarize Othello"],
model="lite", # gemini-3.5-flash-lite โ cheap/fast tier for batch
)
The current frontier Flash is gemini-3.8-flash (GA 2026-09-02), the
default and the flash alias. Google shipped three Flash generations in six
weeks: 3.6 (2026-07-21), 3.7 (2026-08-13), 3.8 (2026-09-02). Each stays
callable under a pinned alias (flash-3.7, flash-3.6, flash-3.5,
flash-3), and none has a shutdown date. gemini-3.1-flash-lite-preview from
earlier docs is gone (shut down 2026-05-25).
The Pro tier is off routing. gemini-3.1-pro-preview costs 2.7ร the input and
3.2ร the output of 3.8 Flash at today's rates and loses to the 3.5+ Flash line
on the coding and agentic benchmarks that matter here. Do not target it; the
pro alias now resolves to gemini-3.8-flash, and "maximum reasoning" means
thinking_level='high' on Flash.
| Model | Alias | Input/1M | Output/1M | Context | Notes |
|---|---|---|---|---|---|
| gemini-3.8-flash | flash |
$0.75 โ $1.50 | $3.75 โ $7.50 | 1M in / 64K out | Default. GA 2026-09-02. Current frontier Flash. Vs 3.7: Terminal-Bench 2.1 90.8% vs 81.6%, SWE-Bench Pro 61.6% vs 60.4%, SWE-Atlas 51.9% vs 48.0%, HLE flat (45.4% vs 45.7%). Google says it "works harder" at higher effort, so expect more thinking tokens per task. thinking_level is low/medium/high only โ minimal returns HTTP 400 and the client downgrades it to low. Default medium spent 79 thinking tokens on a one-word reply (measured 2026-09-03); pass low for non-reasoning tasks. |
| gemini-3.7-flash | flash-3.7 |
$0.75 โ $1.50 | $3.75 โ $7.50 | 1M / 64K | GA 2026-08-13. DeepSWE v1.1 65.3% vs 49.0% on 3.6, Terminal-Bench 2.1 85.8%. Same minimal restriction as 3.8. Google keeps it "fully supported for efficiency-first workloads". |
| gemini-3.6-flash | flash-3.6 |
$0.75 โ $1.50 | $3.75 โ $7.50 | 1M / 64K | GA 2026-07-21. ~17% fewer output tokens than 3.5 Flash. Last Flash that accepts thinking_level='minimal' (verified 2026-09-03). |
| gemini-3.5-flash | flash-3.5 |
$1.50 | $9.00 | 1M | GA 2026-05-19. Google's model list now labels it "legacy". Accepts minimal. Costs more on output than 3.6โ3.8. |
| gemini-3-flash-preview | flash-3 |
$0.30 | $2.50 | 1M | Older preview Flash, kept for back compat. Google's listed migration target for it is gemini-3.6-flash; no shutdown date. |
| โ | $2.00 (โค200K) / $4.00 | $12.00 / $18.00 | 1M | DEPRECATED from routing (2026-09-03). Price/quality dominated by 3.6+ Flash; 3.5 Flash already beat it on most coding/agentic benchmarks. ID stays callable for pinned code. pro now resolves to gemini-3.8-flash. 3.5 Pro was announced at I/O 2026-05-19 for June and is still absent from the API as of 2026-09-03; it gets the same price/quality test before any alias points at it. |
|
| gemini-3.5-flash-lite | lite |
$0.30 | $2.50 | 1M | Cheap/bulk tier. GA 2026-07-21. Fastest 3.5-class (350 output tok/sec); beats gemini-3-flash on SWE-Bench Pro and OSWorld-Verified. |
stable-flash |
$0.30 | $2.50 | 1M | DEPRECATED โ 2025-era generation, do not route here. | |
| โ | $0.10 | $0.40 | 1M | DEPRECATED โ cheaper, but a 2025-era generation. lite now resolves to gemini-3.5-flash-lite. |
|
stable-pro |
$1.25 (โค200K) / $2.50 | $10.00 / $20.00 | 1M | DEPRECATED โ 2025-era generation, do not route here. |
$0.75 โ $1.50 means introductory pricing: Google's pricing page (fetched
2026-09-03) lists 3.6, 3.7 and 3.8 Flash at $0.75 in / $3.75 out through
2026-12-31 and $1.50 / $7.50 from 2027-01-01. Context caching is $0.075 โ $0.15;
Batch is half of standard. Output prices include thinking tokens.
| Model | Alias | Input/1M | Per Image |
|---|---|---|---|
| gemini-3.1-flash-image-preview | image, nano-banana-2 |
$0.25 | $0.067 |
| gemini-3-pro-image-preview | image-pro, nano-banana-pro |
$2.00 | $0.134 |
| Model | Alias | Input/1M | Output/1M (audio) | Notes |
|---|---|---|---|---|
| gemini-3.8-flash-tts | tts |
$0.50 โ $1.00 | $9.00 โ $18.00 | GA 2026-09-23. Expressive, 130 languages, 2 speakers. Use generate_speech(), not invoke_gemini(). |
| gemini-3.8-flash-lite-tts | tts-lite |
$0.50 โ $1.00 | $6.00 โ $12.00 | GA 2026-09-23. Bulk / read-aloud, 101 languages. Replaces gemini-3.1-flash-tts-preview ($1 / $20). |
Speech aliases live in SPEECH_ALIASES, not MODEL_ALIASES, so a text call can
never resolve to an audio model.
See references/models.md for full details.
Gemini 3.x models reason before responding. The parameter changed in
2026: integer thinking_budget is gone; use string thinking_level
โ {minimal, low, medium, high}. Default for 3.5โ3.8 Flash is
medium. For transcription / classification / extraction tasks, pass
thinking_level='minimal' or the model will silently spend output
tokens on reasoning (symptom: empty response with
finishReason=MAX_TOKENS).
3.7 and 3.8 Flash reject minimal with HTTP 400 (Thinking level MINIMAL is not supported for this model); low is their floor. The client downgrades
minimal to low on those two models and prints a note to stderr, so existing
callers keep working. Measured on 3.8 (2026-09-03): low spent 0 thinking
tokens on a one-word reply, the default medium spent 79. On 3.7, low still
spent 45โ88, and a max_output_tokens=50 call at low hit MAX_TOKENS and
returned None, so budget output generously there. If a job needs a true
no-thinking pass, pin flash-3.6 or lite, which still accept minimal.
response = invoke_gemini(
prompt="Transcribe this image.",
model="flash",
image_path="/tmp/screenshot.png",
max_output_tokens=4000,
thinking_level="minimal", # don't burn output budget on reasoning
)
response = invoke_gemini(prompt="...", model="flash")
if response is None:
print("API call failed โ check credentials")
result = generate_image("...")
if result is None:
print("Image generation failed โ check credentials or try again")
Common issues: Missing API key โ see Setup. Rate limit โ auto-retries with backoff. Network error โ returns None.
response = invoke_gemini(
prompt="Write a haiku",
model="flash", # gemini-3.8-flash
temperature=0.9,
max_output_tokens=200,
top_p=0.95,
thinking_level="low", # haiku is short; modest reasoning is fine
)
from pydantic import BaseModel
from gemini_client import invoke_with_structured_output
class ImageDescription(BaseModel):
objects: list[str]
scene: str
colors: list[str]
result = invoke_with_structured_output(
prompt="Describe this image",
pydantic_model=ImageDescription,
image_path="/mnt/user-data/uploads/photo.jpg"
)
See references/advanced.md for more patterns.
"No credentials configured": Create /mnt/project/proxy.env with CF credentials, or add GOOGLE_API_KEY.txt.
CF Gateway 401/403: Verify CF_API_TOKEN has AI Gateway permissions. If not using BYOK, add GOOGLE_API_KEY to proxy.env.
Import errors: uv pip install requests pydantic
Image generation returns None: Check credentials. If persistent, try model="nano-banana-2" (more reliable than image-pro). Check for content policy blocks in error output.