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
4 changes: 2 additions & 2 deletions cli-first-tool-schemas.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"schemaVersion": 1,
"generatedAt": "2026-10-14T17:55:57.022Z",
"generatedAt": "2026-10-14T18:25:35.464Z",
"selector": "--help",
"toolCount": 80,
"agentCount": 14,
Expand Down Expand Up @@ -1787,7 +1787,7 @@
"type": "string",
"required": false,
"positional": false,
"description": "[OPTIONAL] Image generation model (default: gemini-3.1-flash-image). Available: gemini-3.1-flash-lite-image, gemini-3.1-flash-image, gemini-nano-banana-2.1, gemini-3-pro-image, gpt-5.4-image-2, flux-2-pro, flux-2-flex, flux-2-klein-4b, gpt-image-2, seedream-4.5, seedream-5-lite, gpt-image-2.5-sunburst, gpt-image-2.5-flare, flux-3-image, seedream-5-pro, seedream-5-flash (One of: [\"gemini-3.1-flash-lite-image\", \"gemini-3.1-flash-image\", \"gemini-nano-banana-2.1\", \"gemini-3-pro-image\", \"gpt-5.4-image-2\", \"flux-2-pro\", \"flux-2-flex\", \"flux-2-klein-4b\", \"gpt-image-2\", \"seedream-4.5\", \"seedream-5-lite\", \"gpt-image-2.5-sunburst\", \"gpt-image-2.5-flare\", \"flux-3-image\", \"seedream-5-pro\", \"seedream-5-flash\"])"
"description": "[OPTIONAL] Image generation model (default: gemini-3.1-flash-image). Available: gemini-nano-banana-2.1, gemini-3.1-flash-lite-image, gemini-3.1-flash-image, gemini-3-pro-image, gpt-5.4-image-2, flux-2-pro, flux-2-flex, flux-2-klein-4b, gpt-image-2, seedream-4.5, seedream-5-lite, gpt-image-2.5-sunburst, gpt-image-2.5-flare, flux-3-image, seedream-5-pro, seedream-5-flash (One of: [\"gemini-nano-banana-2.1\", \"gemini-3.1-flash-lite-image\", \"gemini-3.1-flash-image\", \"gemini-3-pro-image\", \"gpt-5.4-image-2\", \"flux-2-pro\", \"flux-2-flex\", \"flux-2-klein-4b\", \"gpt-image-2\", \"seedream-4.5\", \"seedream-5-lite\", \"gpt-image-2.5-sunburst\", \"gpt-image-2.5-flare\", \"flux-3-image\", \"seedream-5-pro\", \"seedream-5-flash\"])"
},
{
"name": "aspectRatio",
Expand Down
1 change: 1 addition & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
- Google-direct video generation now uses **Gemini Omni Flash** (`gemini-omni-1.1-flash`) through Google's Interactions API. Google shuts down every Veo 3.1 preview model on 2026-10-22 and names Omni as the replacement. Omni makes 3 to 10 second clips at 16:9 or 9:16, in 360p, 720p, 1080p or 4K, always with audio, and can start from a reference image. A negative prompt is added to the prompt as "Do not include: ...", because Omni has no separate field for it. Veo 3.1 and Veo 3.1 Fast through OpenRouter are unchanged, and Veo 3.1 Fast via OpenRouter stays the default video model.
- The Veo 3.1 preview models are gone from the Google video list. A saved default, or a `generateVideo` call, that names one runs on Gemini Omni Flash and keeps its aspect ratio and resolution. The result says which model was used instead.
- Image models that are shut down or scheduled to shut down are removed: GPT Image 1, 1.5 and 1 Mini (OpenAI), Gemini 2.5 Flash Image and the Gemini 3.1 Flash Image and 3 Pro Image previews (Google and OpenRouter), and GPT-5 Image and GPT-5 Image Mini (OpenRouter, built on GPT Image 1). A saved default, a conversation's image model, or a `generateImage` call that names one uses the provider's documented replacement: GPT Image 2.5 Sunburst for GPT Image 1, 1.5 and GPT-5 Image; GPT Image 2.5 Flare for the Mini models; Nano Banana 2 Lite for Gemini 2.5 Flash Image; Nano Banana 2.1 and Nano Banana Pro for the previews. A saved Gemini 2.5 Flash Image default used to move to Nano Banana 2; it now follows Google's recommendation, Nano Banana 2 Lite.
- **Nano Banana 2.1 is the default image model** for new installs and wherever no image model is chosen, on Google direct and OpenRouter. Google recommends it over Nano Banana 2 (`gemini-3.1-flash-image`, now deprecated with no shutdown date) at half the price. A saved image model choice is not changed. Nano Banana 2.1 starts at 1K; it has no 512px size.
- These replacements are applied when settings load and are not written back to your settings file, so other devices that sync it and still run an older Nexus are not affected. The new id is saved the next time you change that setting.

**Fixes**
Expand Down
4 changes: 2 additions & 2 deletions schemas/5.20.4/cli-tools.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"schemaVersion": 1,
"generatedAt": "2026-10-14T17:55:57.022Z",
"generatedAt": "2026-10-14T18:25:35.464Z",
"selector": "--help",
"toolCount": 80,
"agentCount": 14,
Expand Down Expand Up @@ -1787,7 +1787,7 @@
"type": "string",
"required": false,
"positional": false,
"description": "[OPTIONAL] Image generation model (default: gemini-3.1-flash-image). Available: gemini-3.1-flash-lite-image, gemini-3.1-flash-image, gemini-nano-banana-2.1, gemini-3-pro-image, gpt-5.4-image-2, flux-2-pro, flux-2-flex, flux-2-klein-4b, gpt-image-2, seedream-4.5, seedream-5-lite, gpt-image-2.5-sunburst, gpt-image-2.5-flare, flux-3-image, seedream-5-pro, seedream-5-flash (One of: [\"gemini-3.1-flash-lite-image\", \"gemini-3.1-flash-image\", \"gemini-nano-banana-2.1\", \"gemini-3-pro-image\", \"gpt-5.4-image-2\", \"flux-2-pro\", \"flux-2-flex\", \"flux-2-klein-4b\", \"gpt-image-2\", \"seedream-4.5\", \"seedream-5-lite\", \"gpt-image-2.5-sunburst\", \"gpt-image-2.5-flare\", \"flux-3-image\", \"seedream-5-pro\", \"seedream-5-flash\"])"
"description": "[OPTIONAL] Image generation model (default: gemini-3.1-flash-image). Available: gemini-nano-banana-2.1, gemini-3.1-flash-lite-image, gemini-3.1-flash-image, gemini-3-pro-image, gpt-5.4-image-2, flux-2-pro, flux-2-flex, flux-2-klein-4b, gpt-image-2, seedream-4.5, seedream-5-lite, gpt-image-2.5-sunburst, gpt-image-2.5-flare, flux-3-image, seedream-5-pro, seedream-5-flash (One of: [\"gemini-nano-banana-2.1\", \"gemini-3.1-flash-lite-image\", \"gemini-3.1-flash-image\", \"gemini-3-pro-image\", \"gpt-5.4-image-2\", \"flux-2-pro\", \"flux-2-flex\", \"flux-2-klein-4b\", \"gpt-image-2\", \"seedream-4.5\", \"seedream-5-lite\", \"gpt-image-2.5-sunburst\", \"gpt-image-2.5-flare\", \"flux-3-image\", \"seedream-5-pro\", \"seedream-5-flash\"])"
},
{
"name": "aspectRatio",
Expand Down
2 changes: 1 addition & 1 deletion schemas/5.20.4/mcp-tools.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"schemaVersion": 1,
"nexusVersion": "5.20.4",
"generatedAt": "2026-10-14T17:55:57.022Z",
"generatedAt": "2026-10-14T18:25:35.464Z",
"toolCount": 2,
"tools": [
{
Expand Down
5 changes: 3 additions & 2 deletions src/agents/promptManager/tools/generateImage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
getRetiredImageModel,
type RetiredModel
} from '../../../services/llm/types/RetiredMediaModels';
import { DEFAULT_IMAGE_MODEL } from '../../../services/llm/types/ImageTypes';

export interface GenerateImageParams extends CommonParameters {
prompt: string;
Expand Down Expand Up @@ -233,7 +234,7 @@ export class GenerateImageTool extends BaseTool<GenerateImageParams, GenerateIma
}
}
if (!model) {
model = 'gemini-3.1-flash-image';
model = DEFAULT_IMAGE_MODEL;
}

// A saved prompt, conversation or agent may still name a retired id; run
Expand Down Expand Up @@ -267,7 +268,7 @@ export class GenerateImageTool extends BaseTool<GenerateImageParams, GenerateIma
}

// Minimal fallback — only the most common default model
return ['gemini-3.1-flash-image'];
return [DEFAULT_IMAGE_MODEL];
}

/**
Expand Down
39 changes: 21 additions & 18 deletions src/services/llm/adapters/google/GeminiImageAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import {
StreamChunk
} from '../types';
import { readImageDimensions, sniffImageFormat } from '../shared/imageDimensions';
import { DEFAULT_IMAGE_MODEL } from '../../types/ImageTypes';

type OutputFormat = 'png' | 'jpeg' | 'webp';
type GeminiImageSize = '512' | '1K' | '2K' | '4K';
Expand Down Expand Up @@ -128,6 +129,23 @@ const ASPECT_RATIO_TO_DIMENSIONS: Record<string, [number, number]> = {
};

export const GEMINI_IMAGE_MODEL_SPECS: Readonly<Record<string, GeminiImageModelSpec>> = {
// First on purpose: the generateImage tool and the chat image picker fall
// back to a provider's first catalog entry, and this is the default (DEFAULT_IMAGE_MODEL).
// GA 2026-10-06; Google's recommended successor to gemini-3.1-flash-image.
// Half the image-token price of Nano Banana 2 and no 512 size. The Gemini
// docs now show only Interactions API samples; the model page lists Batch
// API support, which is a generateContent-only feature.
// https://ai.google.dev/gemini-api/docs/models/gemini-nano-banana-2.1
'gemini-nano-banana-2.1': {
displayName: 'Nano Banana 2.1',
costPerImage: 0.0336,
pricingNote: '1120 image tokens at $30/M for 1K; 2K is $0.0504 (1680 tokens), 4K $0.113 (3780 tokens)',
imageTokenPricePerMillion: 30,
maxReferenceImages: 14,
imageSizes: ['1K', '2K', '4K'],
contextWindow: 131072,
lastUpdated: '2026-10-14'
},
'gemini-3.1-flash-lite-image': {
displayName: 'Nano Banana 2 Lite',
costPerImage: 0.0336,
Expand All @@ -148,21 +166,6 @@ export const GEMINI_IMAGE_MODEL_SPECS: Readonly<Record<string, GeminiImageModelS
contextWindow: 65536,
lastUpdated: '2026-09-02'
},
// GA 2026-10-06; Google's recommended successor to gemini-3.1-flash-image.
// Half the image-token price of Nano Banana 2 and no 512 size. The Gemini
// docs now show only Interactions API samples; the model page lists Batch
// API support, which is a generateContent-only feature.
// https://ai.google.dev/gemini-api/docs/models/gemini-nano-banana-2.1
'gemini-nano-banana-2.1': {
displayName: 'Nano Banana 2.1',
costPerImage: 0.0336,
pricingNote: '1120 image tokens at $30/M for 1K; 2K is $0.0504 (1680 tokens), 4K $0.113 (3780 tokens)',
imageTokenPricePerMillion: 30,
maxReferenceImages: 14,
imageSizes: ['1K', '2K', '4K'],
contextWindow: 131072,
lastUpdated: '2026-10-14'
},
'gemini-3-pro-image': {
displayName: 'Nano Banana Pro',
costPerImage: 0.134,
Expand Down Expand Up @@ -194,7 +197,7 @@ export class GeminiImageAdapter extends BaseImageAdapter {
readonly supportedFormats: string[] = ['png', 'jpeg', 'webp'];

private vault: Vault | null = null;
private readonly defaultModel = 'gemini-3.1-flash-image';
private readonly defaultModel = DEFAULT_IMAGE_MODEL;

// Supported aspect ratios for Nano Banana models
private readonly nanoBananaAspectRatios: string[] = [
Expand All @@ -204,7 +207,7 @@ export class GeminiImageAdapter extends BaseImageAdapter {

constructor(config?: ProviderConfig & { vault?: Vault }) {
const apiKey = config?.apiKey || '';
super(apiKey, 'gemini-3.1-flash-image', config?.baseUrl);
super(apiKey, DEFAULT_IMAGE_MODEL, config?.baseUrl);

if (config?.vault) {
this.vault = config.vault;
Expand Down Expand Up @@ -463,7 +466,7 @@ export class GeminiImageAdapter extends BaseImageAdapter {
* List price for one 1K image. The actual charge is computed from the
* response's image token count and recorded as `metadata.reportedCostUsd`.
*/
getImageModelPricing(model = 'gemini-3.1-flash-image'): Promise<CostDetails> {
getImageModelPricing(model: string = DEFAULT_IMAGE_MODEL): Promise<CostDetails> {
const basePrice = this.modelSpecs[model]?.costPerImage ?? 0.039;

return Promise.resolve({
Expand Down
31 changes: 16 additions & 15 deletions src/services/llm/adapters/openrouter/OpenRouterImageAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import {
} from '../types';
import { BRAND_NAME } from '../../../../constants/branding';
import { readImageDimensions, sniffImageFormat } from '../shared/imageDimensions';
import { DEFAULT_IMAGE_MODEL } from '../../types/ImageTypes';

type OutputFormat = 'png' | 'jpeg' | 'webp';

Expand Down Expand Up @@ -126,7 +127,18 @@ const ASPECT_RATIO_TO_DIMENSIONS: Record<string, [number, number]> = {
*/
export const OPENROUTER_IMAGE_MODEL_SPECS: Readonly<Record<string, OpenRouterImageModelSpec>> = {
// First on purpose: the generateImage tool and the chat image picker fall
// back to a provider's first catalog entry, and this is the adapter default.
// back to a provider's first catalog entry, and this is the default (DEFAULT_IMAGE_MODEL).
// Added 2026-10-14 from /api/v1/images/models/<id>/endpoints.
'gemini-nano-banana-2.1': {
openRouterId: 'google/gemini-nano-banana-2.1',
displayName: 'Nano Banana 2.1 (via OpenRouter)',
costPerImage: 0.0336,
pricingNote: '1120 output tokens at $30/M for 1K; 2K and 4K use more tokens; no 512',
maxReferenceImages: 14,
resolutions: ['1K', '2K', '4K'],
contextWindow: 65536,
lastUpdated: '2026-10-14'
},
'gemini-3.1-flash-image': {
openRouterId: 'google/gemini-3.1-flash-image',
displayName: 'Nano Banana 2 (via OpenRouter)',
Expand Down Expand Up @@ -229,17 +241,6 @@ export const OPENROUTER_IMAGE_MODEL_SPECS: Readonly<Record<string, OpenRouterIma
contextWindow: 32000,
lastUpdated: '2026-09-02'
},
// Added 2026-10-14 from /api/v1/images/models/<id>/endpoints.
'gemini-nano-banana-2.1': {
openRouterId: 'google/gemini-nano-banana-2.1',
displayName: 'Nano Banana 2.1 (via OpenRouter)',
costPerImage: 0.0336,
pricingNote: '1120 output tokens at $30/M for 1K; 2K and 4K use more tokens; no 512',
maxReferenceImages: 14,
resolutions: ['1K', '2K', '4K'],
contextWindow: 65536,
lastUpdated: '2026-10-14'
},
'gpt-image-2.5-sunburst': {
openRouterId: 'openai/gpt-image-2.5-sunburst',
displayName: 'GPT Image 2.5 Sunburst (via OpenRouter)',
Expand Down Expand Up @@ -316,7 +317,7 @@ export class OpenRouterImageAdapter extends BaseImageAdapter {
private httpReferer: string;
private xTitle: string;

private readonly defaultModel = 'gemini-3.1-flash-image';
private readonly defaultModel = DEFAULT_IMAGE_MODEL;

// Aspect ratios accepted across the catalog. Individual endpoints may
// support fewer; OpenRouter rejects those with a 400 naming the parameter.
Expand All @@ -327,7 +328,7 @@ export class OpenRouterImageAdapter extends BaseImageAdapter {

constructor(config?: ProviderConfig & { vault?: Vault; httpReferer?: string; xTitle?: string }) {
const apiKey = config?.apiKey || '';
super(apiKey, 'gemini-3.1-flash-image', config?.baseUrl);
super(apiKey, DEFAULT_IMAGE_MODEL, config?.baseUrl);

if (config?.vault) {
this.vault = config.vault;
Expand Down Expand Up @@ -574,7 +575,7 @@ export class OpenRouterImageAdapter extends BaseImageAdapter {
* Per-image list price at the default resolution. The actual charge is in
* the response's `usage.cost` and is recorded as `metadata.reportedCostUsd`.
*/
getImageModelPricing(model = 'gemini-3.1-flash-image'): Promise<CostDetails> {
getImageModelPricing(model: string = DEFAULT_IMAGE_MODEL): Promise<CostDetails> {
const basePrice = this.modelSpecs[model]?.costPerImage ?? 0.05;

return Promise.resolve({
Expand Down
12 changes: 10 additions & 2 deletions src/services/llm/types/ImageTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,14 @@

import { CostDetails, LLMProviderError } from '../adapters/types';

/**
* The default image model, shared by Google direct and OpenRouter (both catalog
* it under this id, first in their catalogs). Every fallback reads this
* constant; do not repeat the literal. Google recommends Nano Banana 2.1 over
* gemini-3.1-flash-image (now deprecated, no shutdown date) at half the price.
*/
export const DEFAULT_IMAGE_MODEL = 'gemini-nano-banana-2.1';

// Core image generation parameter interfaces
export interface ImageGenerationParams {
prompt: string;
Expand Down Expand Up @@ -245,13 +253,13 @@ export type ImageModel =
| 'flux-2-pro' // Black Forest Labs FLUX.2 Pro (OpenRouter only)
| 'flux-2-flex' // Black Forest Labs FLUX.2 Flex (OpenRouter only)
| 'flux-2-klein-4b' // Black Forest Labs FLUX.2 Klein 4B (OpenRouter only)
| 'gemini-3.1-flash-image' // Google Nano Banana 2, GA id, the default (Google direct and OpenRouter)
| 'gemini-3.1-flash-image' // Google Nano Banana 2, GA id (deprecated by Google in favour of 2.1, no shutdown date)
| 'gemini-3.1-flash-lite-image' // Google Nano Banana 2 Lite (Google direct and OpenRouter)
| 'gemini-3-pro-image' // Google Nano Banana Pro, GA id (Google direct and OpenRouter)
| 'gpt-image-2' // OpenAI GPT Image 2 (OpenRouter, and the OpenAI adapter)
| 'seedream-4.5' // ByteDance Seedream 4.5 (OpenRouter only)
| 'seedream-5-lite' // ByteDance Seedream 5.0 Lite (OpenRouter only)
| 'gemini-nano-banana-2.1' // Google Nano Banana 2.1 (Google direct and OpenRouter)
| 'gemini-nano-banana-2.1' // Google Nano Banana 2.1, the default (Google direct and OpenRouter)
| 'flux-3-image' // Black Forest Labs FLUX.3 Image (OpenRouter only)
| 'seedream-5-pro' // ByteDance Seedream 5.0 Pro (OpenRouter only)
| 'seedream-5-flash'; // ByteDance Seedream 5.0 Flash (OpenRouter only)
Expand Down
3 changes: 2 additions & 1 deletion src/settings/tabs/DefaultsTab.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { SemanticSearchSettings, type SemanticSearchRuntime } from './defaults/S
import { SemanticSearchOffModal } from './defaults/SemanticSearchOffModal';
import { ConfirmModal } from '../components/ConfirmModal';
import { SEMANTIC_DELETE_MODAL_COPY } from '../../components/shared/chatSettings/copy';
import { DEFAULT_IMAGE_MODEL } from '../../services/llm/types/ImageTypes';

export interface DefaultsTabServices {
app: App;
Expand Down Expand Up @@ -139,7 +140,7 @@ export class DefaultsTab {
agentTemperature: llmSettings?.agentTemperature,
agentContextWindowOverrides: { ...(llmSettings?.agentContextWindowOverrides ?? {}) },
imageProvider: llmSettings?.defaultImageModel?.provider || 'google',
imageModel: llmSettings?.defaultImageModel?.model || 'gemini-3.1-flash-image',
imageModel: llmSettings?.defaultImageModel?.model || DEFAULT_IMAGE_MODEL,
speechProvider: speechChosen ? speech?.provider : undefined,
speechModel: speechChosen ? speech?.model : undefined,
speechVoice: speechChosen ? speech?.voice : undefined,
Expand Down
3 changes: 2 additions & 1 deletion src/types/llm/ProviderTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import type { OAuthState } from '../../services/oauth/IOAuthProvider';
import type { VideoAspectRatio, VideoResolution } from '../../services/llm/types/VideoTypes';
import { DEFAULT_IMAGE_MODEL } from '../../services/llm/types/ImageTypes';

/**
* Thinking effort levels - unified across all providers
Expand Down Expand Up @@ -260,7 +261,7 @@ export const DEFAULT_LLM_PROVIDER_SETTINGS: LLMProviderSettings = {
},
defaultImageModel: {
provider: 'google',
model: 'gemini-3.1-flash-image'
model: DEFAULT_IMAGE_MODEL
},
// Veo 3.1 Fast via OpenRouter: GA, on a route that is not being retired, and
// priced like Google-direct Gemini Omni Flash (about $0.10/s at 720p with
Expand Down
3 changes: 2 additions & 1 deletion src/ui/chat/components/ChatSettingsModal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { Settings } from '../../../settings';
import { getContextWindowOverrideKey } from '../utils/ContextWindowSettings';
import { resolveSubagentTarget } from '../../../components/shared/chatSettings/subagentTarget';
import { getRegistryContextWindow } from '../../../services/llm/utils/modelCapabilityLookup';
import { DEFAULT_IMAGE_MODEL } from '../../../services/llm/types/ImageTypes';

/**
* Type for the NexusPlugin with settings property
Expand Down Expand Up @@ -189,7 +190,7 @@ export class ChatSettingsModal extends Modal {
agentTemperature: this.modelAgentManager.getAgentTemperature(),
agentContextWindowOverrides,
imageProvider: this.modelAgentManager.getImageProvider() || llmSettings?.defaultImageModel?.provider || 'google',
imageModel: this.modelAgentManager.getImageModel() || llmSettings?.defaultImageModel?.model || 'gemini-3.1-flash-image',
imageModel: this.modelAgentManager.getImageModel() || llmSettings?.defaultImageModel?.model || DEFAULT_IMAGE_MODEL,
speechProvider: this.modelAgentManager.getSpeechProvider() || llmSettings?.defaultSpeechModel?.provider,
speechModel: this.modelAgentManager.getSpeechModel() || llmSettings?.defaultSpeechModel?.model,
speechVoice: this.modelAgentManager.getSpeechVoice() || llmSettings?.defaultSpeechModel?.voice,
Expand Down
Loading
Loading