Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .env.local.example
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ NEXT_PUBLIC_COMPOSIO_USER_ID=user@example.com
# NEXT_PUBLIC_MAPBOX_ACCESS_TOKEN=your_mapbox_public_token_here

# AI Provider API Keys
# Gemini 3 Pro (Google Generative AI)
# Gemini 3.1 Pro (Google Generative AI)
GEMINI_3_PRO_API_KEY=your_gemini_3_pro_api_key_here

# Supabase Credentials
Expand Down
27 changes: 14 additions & 13 deletions GEMINI_3_PRO_INTEGRATION.md → GEMINI_3.1_PRO_INTEGRATION.md
Original file line number Diff line number Diff line change
@@ -1,39 +1,40 @@
# Gemini 3 Pro Integration
# Gemini 3.1 Pro Integration

## Overview

This document describes the integration of Google's Gemini 3 Pro model into the QCX application. Gemini 3 Pro is Google's most advanced reasoning model with state-of-the-art capabilities for multimodal understanding, coding, and agentic tasks.
This document describes the integration of Google's Gemini 3.1 Pro model into the QCX application. Gemini 3.1 Pro is Google's most advanced reasoning model with state-of-the-art capabilities for multimodal understanding, coding, and agentic tasks.

## Changes Made

### 1. Updated `lib/utils/index.ts`

Added Gemini 3 Pro as a provider option in the `getModel()` function with the following priority order:
Added Gemini 3.1 Pro as a provider option in the `getModel()` function with the following priority order:

1. **xAI (Grok)** - Primary choice if `XAI_API_KEY` is configured
2. **Gemini 3 Pro** - Secondary choice if `GEMINI_3_PRO_API_KEY` is configured *(NEW)*
1. **Gemini 3.1 Pro** - Primary choice if `GEMINI_3_PRO_API_KEY` is configured *(UPDATED PRIORITY)*
2. **xAI (Grok)** - Secondary choice if `XAI_API_KEY` is configured
3. **AWS Bedrock** - Tertiary choice if AWS credentials are configured
4. **OpenAI** - Default fallback if `OPENAI_API_KEY` is configured

The implementation includes:
- Environment variable check for `GEMINI_3_PRO_API_KEY`
- Creation of Google Generative AI client using `createGoogleGenerativeAI()`
- Model identifier: `gemini-3-pro-preview`
- Model identifier: `gemini-3.1-pro-preview`
- Error handling with fallback to the next available provider
- Support for both "Gemini 3" and "Gemini 3.1 Pro" selection identifiers for backward compatibility.

### 2. Updated `.env.local.example`

Added documentation for the new environment variable:

```bash
# AI Provider API Keys
# Gemini 3 Pro (Google Generative AI)
# Gemini 3.1 Pro (Google Generative AI)
GEMINI_3_PRO_API_KEY="your_gemini_3_pro_api_key_here"
```

## Configuration

To use Gemini 3 Pro in your QCX deployment:
To use Gemini 3.1 Pro in your QCX deployment:

1. Obtain a Google AI API key from [Google AI Studio](https://aistudio.google.com/)
2. Add the API key to your `.env.local` file:
Expand All @@ -44,7 +45,7 @@ To use Gemini 3 Pro in your QCX deployment:

## Model Capabilities

Gemini 3 Pro (`gemini-3-pro-preview`) supports:
Gemini 3.1 Pro (`gemini-3.1-pro-preview`) supports:

- **Advanced Reasoning**: State-of-the-art reasoning capabilities with optional thinking modes
- **Multimodal Understanding**: Text, image, and file inputs
Expand All @@ -58,9 +59,9 @@ Gemini 3 Pro (`gemini-3-pro-preview`) supports:
The provider selection follows this priority order:

```
XAI_API_KEY exists? → Use Grok
GEMINI_3_PRO_API_KEY exists? → Use Gemini 3.1 Pro
↓ No
GEMINI_3_PRO_API_KEY exists? → Use Gemini 3 Pro
XAI_API_KEY exists? → Use Grok
↓ No
AWS credentials exist? → Use AWS Bedrock
↓ No
Expand All @@ -70,12 +71,12 @@ OPENAI_API_KEY exists? → Use OpenAI (default)
## Technical Details

- **SDK Package**: `@ai-sdk/google` (already imported in the codebase)
- **Model ID**: `gemini-3-pro-preview`
- **Model ID**: `gemini-3.1-pro-preview`
- **API Endpoint**: Google Generative AI API
- **Vercel AI SDK Compatible**: Yes, fully compatible with the unified interface

## References

- [Google Gemini 3 Documentation](https://ai.google.dev/gemini-api/docs/gemini-3)
- [Google Gemini 3.1 Pro Documentation](https://ai.google.dev/gemini-api/docs/gemini-3)
- [Vercel AI SDK - Google Provider](https://ai-sdk.dev/providers/ai-sdk-providers/google-generative-ai)
- [Google AI Studio](https://aistudio.google.com/)
10 changes: 5 additions & 5 deletions components/settings/components/model-selection-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,19 +43,19 @@ const models = [
badgeVariant: "secondary" as const,
},
{
id: "Gemini 3",
name: "Gemini 3",
description: "Google's next-generation multimodal model, excelling at understanding and processing diverse information.",
id: "Gemini 3.1 Pro",
name: "Gemini 3.1 Pro",
description: "Google's latest reasoning model, excelling at multimodal understanding and complex agentic tasks.",
icon: Sparkles,
badge: "Multimodal",
badge: "Advanced",
badgeVariant: "outline" as const,
},
Comment on lines +46 to 52
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. Legacy model not migrated 🐞 Bug ≡ Correctness

Existing users with a persisted selectedModel value of "Gemini 3" will no longer have a matching
option in the Model Selection UI after the option was renamed to "Gemini 3.1 Pro", so the UI renders
as unselected and the stored value is not upgraded. This contradicts the intended automatic upgrade
behavior and leaves legacy values in the DB indefinitely.
Agent Prompt
### Issue description
Users may still have `users.selectedModel = "Gemini 3"` stored in the database, but the Settings UI no longer offers an option with that value (it now offers only `"Gemini 3.1 Pro"`). This causes the Settings Model Selection UI to render with no option selected, and the persisted value is never upgraded.

### Issue Context
- The ModelSelectionForm’s Select/RadioGroup options are driven by a local `models` array.
- Settings initializes `selectedModel` directly from `getSelectedModel()`.
- `getModel()` has a runtime fallback for legacy "Gemini 3", but this does not migrate the stored value nor fix the Settings UI.

### Fix approach
Implement a one-time migration/mapping from `"Gemini 3"` → `"Gemini 3.1 Pro"` when reading or when initializing the form, and optionally persist the migrated value.

Good options:
1. **Server-side (preferred):** In `getSelectedModel()`, if the DB value is `"Gemini 3"`, update it to `"Gemini 3.1 Pro"` and return the new value.
2. **Client-side:** In Settings `fetchData()`, map `selectedModel === "Gemini 3"` to `"Gemini 3.1 Pro"`, call `form.setValue()` with the mapped value, and optionally call `saveSelectedModel()` to persist.

### Fix Focus Areas
- components/settings/components/settings.tsx[84-99]
- lib/actions/users.ts[146-181]
- components/settings/components/model-selection-form.tsx[28-107]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

{
id: "GPT-5.1",
name: "GPT-5.1",
description: "The cutting-edge of language models, offering unparalleled performance in creative and analytical tasks.",
icon: Zap,
badge: "Advanced",
badge: "Expert",
Comment on lines +46 to +58
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Normalize legacy "Gemini 3" form values before rendering options.

Line 46 removes the old option id, so existing saved values of "Gemini 3" won’t match any SelectItem/RadioGroupItem. Users can see an apparently unselected model despite having one configured.

Suggested patch
+const normalizeModelValue = (value?: string) =>
+  value === "Gemini 3" ? "Gemini 3.1 Pro" : value;
+
 export function ModelSelectionForm({ form }: ModelSelectionFormProps) {
   return (
@@
-              <Select onValueChange={field.onChange} value={field.value}>
+              <Select onValueChange={field.onChange} value={normalizeModelValue(field.value)}>
@@
             <RadioGroup
               onValueChange={field.onChange}
-              value={field.value}
+              value={normalizeModelValue(field.value)}
               className="space-y-3"
             >
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@components/settings/components/model-selection-form.tsx` around lines 46 -
58, Normalize any legacy saved model id "Gemini 3" to the new id "Gemini 3.1
Pro" before comparing against SelectItem/RadioGroupItem options in the
ModelSelectionForm component; update the value used for rendering and selection
checks (the prop/state that feeds SelectItem/RadioGroupItem, e.g.,
selectedModel, value, or defaultValue) to map "Gemini 3" -> "Gemini 3.1 Pro" so
existing saved configs appear selected, and ensure the same normalization is
applied when initializing form state and when persisting changes.

badgeVariant: "outline" as const,
},
];
Expand Down
2 changes: 1 addition & 1 deletion components/settings/components/settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export type SettingsFormValues = z.infer<typeof settingsFormSchema>
const defaultValues: Partial<SettingsFormValues> = {
systemPrompt:
"You are a planetary copilot, an AI assistant designed to help users with information about planets, space exploration, and astronomy. Provide accurate, educational, and engaging responses about our solar system and beyond.",
selectedModel: "Grok 4.2",
selectedModel: "Gemini 3.1 Pro",
users: [],
}

Expand Down
6 changes: 3 additions & 3 deletions lib/agents/tools/geospatial.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -249,14 +249,14 @@ Uses the Mapbox Search Box Text Search API endpoint to power searching for and g

const selectedModel = await getSelectedModel();

if (selectedModel?.includes('gemini') && mapProvider === 'google') {
let feedbackMessage = `Processing geospatial query with Gemini...`;
if (selectedModel?.toLowerCase().includes('gemini') && mapProvider === 'google') {
let feedbackMessage = `Processing geospatial query with Gemini 3.1 Pro...`;
uiFeedbackStream.update(feedbackMessage);

try {
const genAI = new GoogleGenerativeAI(process.env.GEMINI_3_PRO_API_KEY!);
const model = genAI.getGenerativeModel({
model: 'gemini-1.5-pro-latest',
model: 'gemini-3.1-pro-preview',
});

const searchText = (params as any).location || (params as any).query;
Expand Down
31 changes: 16 additions & 15 deletions lib/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,18 +51,19 @@ export async function getModel(requireVision: boolean = false) {
throw new Error('Selected model is not configured.');
}
case 'Gemini 3':
case 'Gemini 3.1 Pro':
if (gemini3ProApiKey) {
const google = createGoogleGenerativeAI({
apiKey: gemini3ProApiKey,
});
try {
return google('gemini-3-pro-preview');
return google('gemini-3.1-pro-preview');
} catch (error) {
console.error('Selected model "Gemini 3" is configured but failed to initialize.', error);
console.error('Selected model "Gemini 3.1 Pro" is configured but failed to initialize.', error);
throw new Error('Failed to initialize selected model.');
}
} else {
console.error('User selected "Gemini 3" but GEMINI_3_PRO_API_KEY is not set.');
console.error('User selected "Gemini 3.1 Pro" but GEMINI_3_PRO_API_KEY is not set.');
throw new Error('Selected model is not configured.');
Comment on lines 53 to 67
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Use the requested model label in Gemini error logs.

Line 62 and Line 66 always log "Gemini 3.1 Pro". If Line 53 ("Gemini 3") hits this branch, telemetry is misleading during migration/debugging. Log selectedModel (optionally with resolved target) instead.

Suggested patch
-            console.error('Selected model "Gemini 3.1 Pro" is configured but failed to initialize.', error);
+            console.error(
+              `Selected model "${selectedModel}" (resolved to "Gemini 3.1 Pro") is configured but failed to initialize.`,
+              error
+            );
             throw new Error('Failed to initialize selected model.');
           }
         } else {
-            console.error('User selected "Gemini 3.1 Pro" but GEMINI_3_PRO_API_KEY is not set.');
+            console.error(
+              `User selected "${selectedModel}" (resolved to "Gemini 3.1 Pro") but GEMINI_3_PRO_API_KEY is not set.`
+            );
             throw new Error('Selected model is not configured.');
         }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/utils/index.ts` around lines 53 - 67, The console.error calls inside the
Gemini branch currently hard-code "Gemini 3.1 Pro"; update those error messages
to use the actual selected model label (the variable used in the switch, e.g.,
selectedModel) and optionally include the resolved target ("gemini-3.1-pro") so
telemetry reflects whether "Gemini 3" or "Gemini 3.1 Pro" was chosen; modify the
two console.error invocations in the case handling that uses gemini3ProApiKey /
createGoogleGenerativeAI(...) to reference selectedModel (and the resolved
target string) instead of the fixed literal.

}
case 'GPT-5.1':
Expand All @@ -78,27 +79,27 @@ export async function getModel(requireVision: boolean = false) {
}
}

// Default behavior: Grok -> Gemini -> Bedrock -> OpenAI
if (xaiApiKey) {
const xai = createXai({
apiKey: xaiApiKey,
baseURL: 'https://api.x.ai/v1',
// Default behavior: Gemini -> Grok -> Bedrock -> OpenAI
if (gemini3ProApiKey) {
const google = createGoogleGenerativeAI({
apiKey: gemini3ProApiKey,
});
try {
return xai('grok-4-fast-non-reasoning');
return google('gemini-3.1-pro-preview');
} catch (error) {
console.warn('xAI API unavailable, falling back to next provider:');
console.warn('Gemini 3.1 Pro API unavailable, falling back to next provider:', error);
}
}

if (gemini3ProApiKey) {
const google = createGoogleGenerativeAI({
apiKey: gemini3ProApiKey,
if (xaiApiKey) {
const xai = createXai({
apiKey: xaiApiKey,
baseURL: 'https://api.x.ai/v1',
});
try {
return google('gemini-3-pro-preview');
return xai('grok-4-fast-non-reasoning');
} catch (error) {
console.warn('Gemini 3 Pro API unavailable, falling back to next provider:', error);
console.warn('xAI API unavailable, falling back to next provider:');
}
}

Expand Down