AI Agent Integration
This skill teaches agents how to integrate Gemini AI agents into features using Structured Output, URL Context, Function Calling, and other advanced Gemini features.
When to Use
- •When integrating Gemini AI into features
- •When implementing AI agents (ProfileExtractor, ProfileEnhancer, ProfileValidator, etc.)
- •When using Structured Output for predictable AI responses
- •When enriching data from URLs (websites, LinkedIn)
- •When implementing function calling for agent actions
- •When using Thinking Mode for complex reasoning
Core Principles
Gemini SDK Setup
Import SDK:
import { GoogleGenAI } from "npm:@google/genai";
Initialize Client:
const ai = new GoogleGenAI({ apiKey: Deno.env.get('GEMINI_API_KEY') });
Always keep API keys server-side — never expose to frontend.
Model Selection
| Model | Best For | Speed | Cost |
|---|---|---|---|
gemini-2.5-flash-preview | Fast tasks, high throughput | Fast | Low |
gemini-2.5-pro | Complex reasoning, planning | Moderate | Medium |
gemini-3-pro-preview | Complex reasoning, Thinking Mode | Slower | Higher |
Structured Output (JSON Schema)
Basic Pattern
Use Structured Output for predictable responses:
import { Type } from "npm:@google/genai";
const schema = {
type: Type.OBJECT,
properties: {
name: { type: Type.STRING },
industry: { type: Type.STRING },
description: { type: Type.STRING },
},
required: ['name', 'industry'],
};
const response = await ai.models.generateContent({
model: 'gemini-2.5-flash-preview',
contents: prompt,
config: {
responseMimeType: "application/json",
responseSchema: schema,
},
});
const result = JSON.parse(response.text || "{}");
Common Patterns
Extract company data:
const extractSchema = {
type: Type.OBJECT,
properties: {
companyName: { type: Type.STRING },
tagline: { type: Type.STRING },
industry: { type: Type.STRING },
description: { type: Type.STRING },
},
required: ['companyName', 'industry'],
};
Generate tasks:
const taskSchema = {
type: Type.OBJECT,
properties: {
tasks: {
type: Type.ARRAY,
items: {
type: Type.OBJECT,
properties: {
title: { type: Type.STRING },
priority: { type: Type.STRING, enum: ['high', 'medium', 'low'] },
},
},
},
},
required: ['tasks'],
};
URL Context Tool
Website/LinkedIn Enrichment
Extract data from URLs:
const response = await ai.models.generateContent({
model: "gemini-2.5-flash-preview",
contents: [`Analyze ${url} and extract company information`],
config: {
tools: [{ urlContext: {} }],
},
});
// Check which URLs were retrieved
const metadata = response.candidates?.[0]?.urlContextMetadata;
Use for:
- •Company profile enrichment from website
- •LinkedIn profile data extraction
- •Brand visual identity analysis
- •Market research from URLs
Limit: Up to 20 URLs per request
Function Calling
Basic Pattern
Define function declaration:
import { Type } from "npm:@google/genai";
const functionDeclaration = {
name: 'get_company_data',
description: 'Gets company data from database',
parameters: {
type: Type.OBJECT,
properties: {
companyId: { type: Type.STRING },
},
required: ['companyId'],
},
};
Call with function:
const response = await ai.models.generateContent({
model: 'gemini-2.5-flash-preview',
contents: [{ role: 'user', parts: [{ text: prompt }] }],
config: {
tools: [{ functionDeclarations: [functionDeclaration] }],
},
});
// Check for function call
if (response.functionCalls && response.functionCalls.length > 0) {
const functionCall = response.functionCalls[0];
// Execute function
const result = await executeFunction(functionCall.name, functionCall.args);
// Send result back
}
AI Agents in This Project
ProfileExtractor Agent
Purpose: Extract company information from websites/LinkedIn URLs
Model: gemini-2.5-flash-preview or gemini-3-pro-preview
Features: Structured Output, URL Context
Edge Function: ai-helper → wizard_extract_startup or enrich_company_profile
Use cases:
- •Company profile enrichment from website
- •LinkedIn company profile sync
- •Wizard data extraction
ProfileEnhancer Agent
Purpose: Auto-improve profile copy (tagline, description, differentiator)
Model: gemini-3-pro-preview
Features: Structured Output, Thinking Mode
Edge Function: ai-helper → auto_improve_profile
Use cases:
- •Improving company tagline
- •Enhancing description clarity
- •Refining differentiator statement
ProfileValidator Agent
Purpose: Continuous quality audit, identify strengths/risks
Model: gemini-2.5-flash-preview
Features: Structured Output
Edge Function: ai-helper → validate_profile
Use cases:
- •Profile completion tracking
- •Data quality audits
- •Strengths/risks identification
RiskAnalyzer Agent
Purpose: Analyze business risks and opportunities
Model: gemini-2.5-pro
Features: Structured Output
Edge Function: ai-helper → analyze_risks
Use cases:
- •Risk assessment in dashboard
- •Business health scoring
- •Opportunity identification
TaskGenerator Agent
Purpose: Generate prioritized tasks based on startup profile
Model: gemini-2.5-flash-preview
Features: Structured Output
Edge Function: ai-helper → wizard_generate_tasks
Use cases:
- •Onboarding task generation
- •Task prioritization
- •Action item creation
Thinking Mode (Gemini 3)
When to Use Thinking Mode
Use for complex reasoning:
- •Profile enhancement (ProfileEnhancer)
- •Strategic analysis
- •Multi-step problem solving
Configuration:
const response = await ai.models.generateContent({
model: 'gemini-3-pro-preview',
contents: prompt,
config: {
thinkingLevel: 'high', // 'low' or 'high'
// temperature: 1.0 (default, recommended)
},
});
⚠️ Important:
- •Keep temperature at default 1.0 for Gemini 3
- •Don't use both
thinkingLevelandthinkingBudget - •Thinking Mode adds latency but improves reasoning
Error Handling
Robust Error Handling
try {
const response = await ai.models.generateContent({
model: 'gemini-2.5-flash-preview',
contents: prompt,
config: {
responseMimeType: "application/json",
responseSchema: schema,
},
});
const responseText = response.text || "{}";
if (!responseText || responseText.trim() === "") {
throw new Error("Empty response from model");
}
const parsed = JSON.parse(responseText);
// Validate required fields
for (const field of schema.required || []) {
if (!(field in parsed)) {
throw new Error(`Missing required field: ${field}`);
}
}
return parsed;
} catch (error: any) {
console.error("AI generation error:", error);
throw new Error(`Failed to generate AI response: ${error.message}`);
}
Cost Tracking
Log AI Calls
Track usage in ai_runs table:
const usage = response.usageMetadata;
await supabase.from('ai_runs').insert({
action: 'extract_startup',
model: 'gemini-2.5-flash-preview',
input_tokens: usage.promptTokenCount || 0,
output_tokens: usage.candidatesTokenCount || 0,
total_tokens: usage.totalTokenCount || 0,
cost: calculateCost(usage),
org_id: user.org_id,
created_at: new Date().toISOString(),
});
Best Practices
✅ DO
- •Use Structured Output for predictable responses
- •Specify model based on task complexity
- •Use URL Context for website/LinkedIn enrichment
- •Handle errors gracefully with try-catch
- •Validate parsed responses
- •Log AI calls for cost tracking
- •Keep API keys server-side only
- •Use appropriate model for task (fast vs complex)
❌ DON'T
- •Don't expose API keys to frontend
- •Don't skip error handling
- •Don't forget to validate structured outputs
- •Don't use expensive models for simple tasks
- •Don't skip cost tracking
- •Don't forget CORS handling in Edge Functions
- •Don't use Thinking Mode for simple tasks (adds latency)
Reference
- •Gemini Rules:
.cursor/rules/gemeni/*.mdc(comprehensive Gemini guides) - •Structured Output:
.cursor/rules/gemeni/structured-output.mdc - •URL Context:
.cursor/rules/gemeni/url-context.mdc - •Function Calling:
.cursor/rules/gemeni/function-calling.mdc - •Gemini 3:
.cursor/rules/gemeni/gemeni-3.mdc - •Edge Functions:
.cursor/rules/supabase/writing-supabase-edge-functions.mdc
Created: 2025-01-16
Based on: Gemini AI integration patterns
Version: 1.0.0