Gemini API Best Practices
When reviewing or modifying Gemini API integration code, ensure compliance with Google's official best practices from google-gemini/gemini-skills.
SDK and Package
- Correct SDK:
@google/genai(npm) - NEVER use deprecated:
@google/generative-ai(old package) - Prefer environment variables for API keys over hard-coding
Safety Settings
All API calls (generateContent, generateContentStream, chats.create) MUST include safetySettings in the config:
import { HarmCategory, HarmBlockThreshold, type SafetySetting } from "@google/genai";
const DEFAULT_SAFETY_SETTINGS: SafetySetting[] = [
{ category: HarmCategory.HARM_CATEGORY_HARASSMENT, threshold: HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE },
{ category: HarmCategory.HARM_CATEGORY_HATE_SPEECH, threshold: HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE },
{ category: HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT, threshold: HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE },
{ category: HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT, threshold: HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE },
];
Response Validation (finishReason)
Always check finishReason on response candidates:
SAFETY- Response blocked by safety filters; inform user to rephraseRECITATION- Blocked due to potential copyrighted content recitationMAX_TOKENS- Output truncated; consider informing userSTOP- Normal completion
import { FinishReason } from "@google/genai";
// Check candidates[0].finishReason after each response
if (candidate.finishReason === FinishReason.SAFETY) {
// Handle blocked response
}
For non-streaming: check response.candidates[0].finishReason before using response.text.
For streaming: check finishReason in chunk candidates.
System Instructions
- Pass via
systemInstructionin config (not as a chat message) - System instructions are interaction-scoped; re-specify on each chat session creation
Tool / Function Calling
- Pass tools via
config.toolsarray - Use proper SDK types (
Tool,FunctionDeclaration) without forcedascasts googleSearchandfileSearchare first-classToolpropertiesfileSearchCANNOT be combined withfunctionDeclarationsin the same requestgoogleSearchCANNOT be combined withfunctionDeclarations
Streaming
- Use
generateContentStreamorchat.sendMessageStreamfor streaming - Use SDK Chat (
ai.chats.create()) for automatic thought signature handling - Process ALL parts in each chunk (text, thought, functionCall can coexist)
Thinking / Reasoning
- Thinking is ON by default for Gemini 2.5+ and 3.x models
thinkingBudget: 0disables thinking (except models that require it)- Gemini 3.1 Flash Lite uses
thinkingLevelinstead ofthinkingBudget - Gemini 3 Pro / 3.1 Pro require thinking (cannot be disabled)
- Access thought parts via
part.thoughtboolean on content parts
Model Names
Current models (use these):
gemini-3.1-pro-preview- Flagship, 1M contextgemini-3-flash-preview- Fast, balancedgemini-3.1-flash-lite-preview- Cost-efficientgemini-2.5-pro/gemini-2.5-flash- Still available
Deprecated models (NEVER use):
- All
gemini-2.0-*,gemini-1.5-*,gemini-1.0-*,gemini-pro
Type Safety
- Use proper SDK types from
@google/genaiinstead ofascasts Toolinterface supportsgoogleSearch,fileSearch,functionDeclarations,codeExecution,urlContext- Import enums (
FinishReason,HarmCategory,HarmBlockThreshold) as values, not just types
Checklist for New API Calls
-
safetySettings: DEFAULT_SAFETY_SETTINGSincluded in config -
finishReasonchecked on response candidates -
systemInstructionpassed in config (not as message) - No forced
as Tooltype assertions - Proper error handling with
formatError() - Usage metadata extracted for cost tracking
Source: takeshy/obsidian-gemini-helper — distributed by TomeVault.