Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
42c9b3e
Added fully functioning Agent Tool supporting Google's Nano Banana
devilb2103 Sep 10, 2025
8f7e48c
Merge branch 'dev' into Gemini-Nano-Banana
devilb2103 Sep 10, 2025
3402104
Merge branch 'dev' into Gemini-Nano-Banana
devilb2103 Sep 11, 2025
ec0da5c
Merge branch 'dev' into Gemini-Nano-Banana
devilb2103 Sep 11, 2025
1b5ab4c
🔧 refactor: Update Google credentials handling in GeminiImageGen.js
devilb2103 Sep 13, 2025
074d470
Merge branch 'dev' into Gemini-Nano-Banana
devilb2103 Sep 13, 2025
8b7285b
Merge branch 'dev' into Gemini-Nano-Banana
devilb2103 Nov 11, 2025
f62a70c
🛠️ refactor: Remove unnecessary whitespace in handleTools.js
devilb2103 Nov 11, 2025
f5bb090
Merge branch 'dev' into Gemini-Nano-Banana
devilb2103 Nov 23, 2025
a04211b
Merge branch 'dev' into Gemini-Nano-Banana
devilb2103 Nov 26, 2025
c0b080a
🔧 update: Upgrade @google/genai to version 1.19.0 and replace PNG ico…
devilb2103 Nov 26, 2025
9cc4ae3
✨ feat: Introduce createImageToolContext for Image Tools
devilb2103 Nov 26, 2025
b0d44ca
.
devilb2103 Nov 26, 2025
67bab81
🔧 refactor: Migrate GeminiImageGen tool from CommonJS to ts and updat…
devilb2103 Nov 26, 2025
eac3122
✨ feat: Extend image generation support for Gemini tool
devilb2103 Nov 26, 2025
36eb938
🗑️ chore: Remove outdated README for Gemini Image Generation Tool
devilb2103 Nov 26, 2025
cfe3d6a
🔧 refactor: Improve provider detection and error handling in GeminiIm…
devilb2103 Nov 26, 2025
2901bea
🔧 refactor: Simplify credentials path handling in GeminiImageGen
devilb2103 Nov 26, 2025
4c0876b
Merge branch 'dev' into Gemini-Nano-Banana
devilb2103 Nov 26, 2025
aa0bc63
Merge branch 'dev' into Gemini-Nano-Banana
devilb2103 Nov 29, 2025
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
7 changes: 7 additions & 0 deletions api/app/clients/tools/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -179,5 +179,12 @@
"description": "Provide your Flux API key from your user profile."
}
]
},
{
"name": "Gemini Image Tools",
"pluginKey": "gemini_image_gen",
"description": "Generate high-quality images using Google's Gemini Image Models. Supports both Gemini API (GEMINI_API_KEY) and Vertex AI (service account).",
"icon": "/assets/gemini_image_gen.svg",
"authConfig": []
}
]
48 changes: 30 additions & 18 deletions api/app/clients/tools/util/handleTools.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ const {
createSafeUser,
mcpToolPattern,
loadWebSearchAuth,
createImageToolContext,
GeminiImageGen,
} = require('@librechat/api');
const {
Tools,
Expand Down Expand Up @@ -38,11 +40,13 @@ const {
} = require('../');
const { primeFiles: primeCodeFiles } = require('~/server/services/Files/Code/process');
const { createFileSearchTool, primeFiles: primeSearchFiles } = require('./fileSearch');
const { getStrategyFunctions } = require('~/server/services/Files/strategies');
const { getUserPluginAuthValue } = require('~/server/services/PluginService');
const { createMCPTool, createMCPTools } = require('~/server/services/MCP');
const { loadAuthValues } = require('~/server/services/Tools/credentials');
const { getMCPServerTools } = require('~/server/services/Config');
const { getRoleByName } = require('~/models/Role');
const { getFiles } = require('~/models/File');

/**
* Validates the availability and authentication of tools for a user based on environment variables or user-specific plugin authentication values.
Expand Down Expand Up @@ -179,6 +183,7 @@ const loadTools = async ({
'azure-ai-search': StructuredACS,
traversaal_search: TraversaalSearch,
tavily_search_results_json: TavilySearchResults,
gemini_image_gen: GeminiImageGen,
};

const customConstructors = {
Expand All @@ -191,24 +196,10 @@ const loadTools = async ({
const authFields = getAuthFields('image_gen_oai');
const authValues = await loadAuthValues({ userId: user, authFields });
const imageFiles = options.tool_resources?.[EToolResources.image_edit]?.files ?? [];
let toolContext = '';
for (let i = 0; i < imageFiles.length; i++) {
const file = imageFiles[i];
if (!file) {
continue;
}
if (i === 0) {
toolContext =
'Image files provided in this request (their image IDs listed in order of appearance) available for image editing:';
}
toolContext += `\n\t- ${file.file_id}`;
if (i === imageFiles.length - 1) {
toolContext += `\n\nInclude any you need in the \`image_ids\` array when calling \`${EToolResources.image_edit}_oai\`. You may also include previously referenced or generated image IDs.`;
}
}
if (toolContext) {
toolContextMap.image_edit_oai = toolContext;
}
createImageToolContext(imageFiles, toolContextMap, {
toolKey: 'image_edit_oai',
purpose: 'image editing',
});
return createOpenAIImageTools({
...authValues,
isAgent: !!agent,
Expand All @@ -218,6 +209,26 @@ const loadTools = async ({
imageFiles,
});
},
gemini_image_gen: async (toolContextMap) => {
const authFields = getAuthFields('gemini_image_gen');
const authValues = await loadAuthValues({ userId: user, authFields });
const imageFiles = options.tool_resources?.[EToolResources.image_edit]?.files ?? [];
createImageToolContext(imageFiles, toolContextMap, {
toolKey: 'gemini_image_gen',
purpose: 'image context',
});
return new GeminiImageGen({
...authValues,
isAgent: !!agent,
req: options.req,
imageFiles,
processFileURL: options.processFileURL,
userId: user,
fileStrategy: options.fileStrategy,
getFiles,
getStrategyFunctions,
});
},
};

const requestedTools = {};
Expand All @@ -240,6 +251,7 @@ const loadTools = async ({
flux: imageGenOptions,
dalle: imageGenOptions,
'stable-diffusion': imageGenOptions,
gemini_image_gen: imageGenOptions,
};

/** @type {Record<string, string>} */
Expand Down
1 change: 1 addition & 0 deletions api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
"@azure/search-documents": "^12.0.0",
"@azure/storage-blob": "^12.27.0",
"@google/generative-ai": "^0.24.0",
"@google/genai": "^1.19.0",
"@googleapis/youtube": "^20.0.0",
"@keyv/redis": "^4.3.3",
"@langchain/core": "^0.3.79",
Expand Down
3 changes: 2 additions & 1 deletion api/server/services/start/tools.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const { Calculator } = require('@librechat/agents');
const { logger } = require('@librechat/data-schemas');
const { zodToJsonSchema } = require('zod-to-json-schema');
const { Tools, ImageVisionTool } = require('librechat-data-provider');
const { getToolkitKey, oaiToolkit, ytToolkit } = require('@librechat/api');
const { getToolkitKey, oaiToolkit, ytToolkit, GeminiImageGen } = require('@librechat/api');
const { toolkits } = require('~/app/clients/tools/manifest');

/**
Expand Down Expand Up @@ -84,6 +84,7 @@ function loadAndFormatTools({ directory, adminFilter = [], adminIncluded = [] })
new Calculator(),
...Object.values(oaiToolkit),
...Object.values(ytToolkit),
new GeminiImageGen({ override: true }),
];
for (const toolInstance of basicToolInstances) {
const formattedTool = formatToOpenAIAssistantTool(toolInstance);
Expand Down
24 changes: 24 additions & 0 deletions client/public/assets/gemini_image_gen.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 3 additions & 1 deletion client/src/components/Chat/Messages/Content/Part.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,9 @@ const Part = memo(
);
} else if (
isToolCall &&
(toolCall.name === 'image_gen_oai' || toolCall.name === 'image_edit_oai')
(toolCall.name === 'image_gen_oai' ||
toolCall.name === 'image_edit_oai' ||
toolCall.name === 'gemini_image_gen')
) {
return (
<OpenAIImageGen
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,22 @@ export default function ProgressText({
return localize('com_ui_getting_started');
}

if (toolName === 'gemini_image_gen') {
if (progress >= 1) {
return localize('com_ui_image_created');
}
if (progress >= 0.7) {
return localize('com_ui_final_touch');
}
if (progress >= 0.5) {
return localize('com_ui_adding_details');
}
if (progress >= 0.3) {
return localize('com_ui_creating_image');
}
return localize('com_ui_getting_started');
}

if (progress >= 1) {
return localize('com_ui_image_created');
}
Expand Down
24 changes: 23 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
"@azure/identity": "^4.7.0",
"@azure/search-documents": "^12.0.0",
"@azure/storage-blob": "^12.27.0",
"@google/genai": "^1.19.0",
"@keyv/redis": "^4.3.3",
"@langchain/core": "^0.3.79",
"@librechat/agents": "^3.0.34",
Expand Down
Loading