mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-04-07 00:15:23 +02:00
Merge dac0667bda into 8ed0bcf5ca
This commit is contained in:
commit
bbd62e1e04
9 changed files with 177 additions and 11 deletions
|
|
@ -353,6 +353,8 @@
|
|||
"com_endpoint_use_active_assistant": "Use Active Assistant",
|
||||
"com_endpoint_use_responses_api": "Use Responses API",
|
||||
"com_endpoint_use_search_grounding": "Grounding with Google Search",
|
||||
"com_endpoint_use_url_context": "URL Context",
|
||||
"com_endpoint_google_use_url_context": "Use Gemini's URL context feature to fetch and use content from URLs in your prompt. Supports up to 20 URLs per request.",
|
||||
"com_endpoint_verbosity": "Verbosity",
|
||||
"com_error_endpoint_models_not_loaded": "Models for {{0}} could not be loaded. Please refresh the page and try again.",
|
||||
"com_error_expired_user_key": "Provided key for {{0}} expired at {{1}}. Please provide a new key and try again.",
|
||||
|
|
|
|||
|
|
@ -634,6 +634,107 @@ describe('getGoogleConfig', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('URL Context Functionality', () => {
|
||||
it('should enable url_context when url_context is true', () => {
|
||||
const credentials = {
|
||||
[AuthKeys.GOOGLE_API_KEY]: 'test-api-key',
|
||||
};
|
||||
|
||||
const result = getGoogleConfig(credentials, {
|
||||
modelOptions: {
|
||||
model: 'gemini-2.5-flash',
|
||||
url_context: true,
|
||||
},
|
||||
});
|
||||
|
||||
expect(result.tools).toContainEqual({ urlContext: {} });
|
||||
});
|
||||
|
||||
it('should not enable url_context when url_context is false', () => {
|
||||
const credentials = {
|
||||
[AuthKeys.GOOGLE_API_KEY]: 'test-api-key',
|
||||
};
|
||||
|
||||
const result = getGoogleConfig(credentials, {
|
||||
modelOptions: {
|
||||
model: 'gemini-2.5-flash',
|
||||
url_context: false,
|
||||
},
|
||||
});
|
||||
|
||||
expect(result.tools).not.toContainEqual({ urlContext: {} });
|
||||
});
|
||||
|
||||
it('should handle url_context with web_search together', () => {
|
||||
const credentials = {
|
||||
[AuthKeys.GOOGLE_API_KEY]: 'test-api-key',
|
||||
};
|
||||
|
||||
const result = getGoogleConfig(credentials, {
|
||||
modelOptions: {
|
||||
model: 'gemini-2.5-flash',
|
||||
web_search: true,
|
||||
url_context: true,
|
||||
},
|
||||
});
|
||||
|
||||
expect(result.tools).toContainEqual({ googleSearch: {} });
|
||||
expect(result.tools).toContainEqual({ urlContext: {} });
|
||||
expect(result.tools).toHaveLength(2);
|
||||
});
|
||||
|
||||
it('should enable url_context via defaultParams', () => {
|
||||
const credentials = {
|
||||
[AuthKeys.GOOGLE_API_KEY]: 'test-api-key',
|
||||
};
|
||||
|
||||
const result = getGoogleConfig(credentials, {
|
||||
modelOptions: {
|
||||
model: 'gemini-2.5-flash',
|
||||
},
|
||||
defaultParams: {
|
||||
url_context: true,
|
||||
},
|
||||
});
|
||||
|
||||
expect(result.tools).toContainEqual({ urlContext: {} });
|
||||
});
|
||||
|
||||
it('should enable url_context via addParams when initially disabled', () => {
|
||||
const credentials = {
|
||||
[AuthKeys.GOOGLE_API_KEY]: 'test-api-key',
|
||||
};
|
||||
|
||||
const result = getGoogleConfig(credentials, {
|
||||
modelOptions: {
|
||||
model: 'gemini-2.5-flash',
|
||||
url_context: false,
|
||||
},
|
||||
addParams: {
|
||||
url_context: true,
|
||||
},
|
||||
});
|
||||
|
||||
expect(result.tools).toContainEqual({ urlContext: {} });
|
||||
});
|
||||
|
||||
it('should disable url_context via dropParams', () => {
|
||||
const credentials = {
|
||||
[AuthKeys.GOOGLE_API_KEY]: 'test-api-key',
|
||||
};
|
||||
|
||||
const result = getGoogleConfig(credentials, {
|
||||
modelOptions: {
|
||||
model: 'gemini-2.5-flash',
|
||||
url_context: true,
|
||||
},
|
||||
dropParams: ['url_context'],
|
||||
});
|
||||
|
||||
expect(result.tools).not.toContainEqual({ urlContext: {} });
|
||||
});
|
||||
});
|
||||
|
||||
describe('Default and Add Parameters', () => {
|
||||
it('should apply default parameters when fields are undefined', () => {
|
||||
const credentials = {
|
||||
|
|
|
|||
|
|
@ -150,6 +150,7 @@ export function getGoogleConfig(
|
|||
|
||||
const {
|
||||
web_search,
|
||||
url_context,
|
||||
thinkingLevel,
|
||||
thinking = googleSettings.thinking.default,
|
||||
thinkingBudget = googleSettings.thinkingBudget.default,
|
||||
|
|
@ -157,6 +158,7 @@ export function getGoogleConfig(
|
|||
} = options.modelOptions || {};
|
||||
|
||||
let enableWebSearch = web_search;
|
||||
let enableUrlContext = url_context;
|
||||
|
||||
const llmConfig: GoogleClientOptions | VertexAIClientOptions = removeNullishValues(
|
||||
{
|
||||
|
|
@ -282,6 +284,14 @@ export function getGoogleConfig(
|
|||
continue;
|
||||
}
|
||||
|
||||
/** Handle url_context separately - don't add to config */
|
||||
if (key === 'url_context') {
|
||||
if (enableUrlContext === undefined && typeof value === 'boolean') {
|
||||
enableUrlContext = value;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (knownGoogleParams.has(key)) {
|
||||
/** Route known Google params to llmConfig only if undefined */
|
||||
applyDefaultParams(llmConfig as Record<string, unknown>, { [key]: value });
|
||||
|
|
@ -301,6 +311,14 @@ export function getGoogleConfig(
|
|||
continue;
|
||||
}
|
||||
|
||||
/** Handle url_context separately - don't add to config */
|
||||
if (key === 'url_context') {
|
||||
if (typeof value === 'boolean') {
|
||||
enableUrlContext = value;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (knownGoogleParams.has(key)) {
|
||||
/** Route known Google params to llmConfig */
|
||||
(llmConfig as Record<string, unknown>)[key] = value;
|
||||
|
|
@ -317,6 +335,11 @@ export function getGoogleConfig(
|
|||
return;
|
||||
}
|
||||
|
||||
if (param === 'url_context') {
|
||||
enableUrlContext = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (param in llmConfig) {
|
||||
delete (llmConfig as Record<string, unknown>)[param];
|
||||
}
|
||||
|
|
@ -329,6 +352,10 @@ export function getGoogleConfig(
|
|||
tools.push({ googleSearch: {} });
|
||||
}
|
||||
|
||||
if (enableUrlContext) {
|
||||
tools.push({ urlContext: {} });
|
||||
}
|
||||
|
||||
// Return the final shape
|
||||
return {
|
||||
/** @type {GoogleAIToolType[]} */
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ const googleExcludeParams = new Set([
|
|||
]);
|
||||
|
||||
/** Google-specific tool types that have no OpenAI-compatible equivalent */
|
||||
const googleToolsToFilter = new Set(['googleSearch']);
|
||||
const googleToolsToFilter = new Set(['googleSearch', 'urlContext']);
|
||||
|
||||
export type ConfigTools = Array<Record<string, unknown>> | Array<GoogleAIToolType>;
|
||||
|
||||
|
|
@ -93,8 +93,8 @@ export function transformToOpenAIConfig({
|
|||
|
||||
if (addParams && typeof addParams === 'object') {
|
||||
for (const [key, value] of Object.entries(addParams)) {
|
||||
/** Skip web_search - it's handled separately as a tool */
|
||||
if (key === 'web_search') {
|
||||
/** Skip web_search and url_context - they're handled separately as tools */
|
||||
if (key === 'web_search' || key === 'url_context') {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -113,8 +113,8 @@ export function transformToOpenAIConfig({
|
|||
|
||||
if (dropParams && Array.isArray(dropParams)) {
|
||||
dropParams.forEach((param) => {
|
||||
/** Skip web_search - handled separately */
|
||||
if (param === 'web_search') {
|
||||
/** Skip web_search and url_context - handled separately as tools */
|
||||
if (param === 'web_search' || param === 'url_context') {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -134,11 +134,13 @@ export function transformToOpenAIConfig({
|
|||
|
||||
/**
|
||||
* Filter out provider-specific tools that have no OpenAI equivalent.
|
||||
* Exception: If web_search was explicitly enabled via addParams or defaultParams,
|
||||
* preserve googleSearch tools (pass through in Google-native format).
|
||||
* Exception: If web_search or url_context was explicitly enabled via addParams or defaultParams,
|
||||
* preserve the corresponding Google-native tools (googleSearch, urlContext).
|
||||
*/
|
||||
const webSearchExplicitlyEnabled =
|
||||
addParams?.web_search === true || defaultParams?.web_search === true;
|
||||
const urlContextExplicitlyEnabled =
|
||||
addParams?.url_context === true || defaultParams?.url_context === true;
|
||||
|
||||
const filterGoogleTool = (tool: unknown): boolean => {
|
||||
if (!isGoogle) {
|
||||
|
|
@ -149,11 +151,18 @@ export function transformToOpenAIConfig({
|
|||
}
|
||||
const toolKeys = Object.keys(tool as Record<string, unknown>);
|
||||
const isGoogleSpecificTool = toolKeys.some((key) => googleToolsToFilter.has(key));
|
||||
/** Preserve googleSearch if web_search was explicitly enabled */
|
||||
if (isGoogleSpecificTool && webSearchExplicitlyEnabled) {
|
||||
return true;
|
||||
if (isGoogleSpecificTool) {
|
||||
const hasGoogleSearch = toolKeys.includes('googleSearch');
|
||||
const hasUrlContext = toolKeys.includes('urlContext');
|
||||
if (hasGoogleSearch && webSearchExplicitlyEnabled) {
|
||||
return true;
|
||||
}
|
||||
if (hasUrlContext && urlContextExplicitlyEnabled) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return !isGoogleSpecificTool;
|
||||
return true;
|
||||
};
|
||||
|
||||
const filteredTools = Array.isArray(tools) ? tools.filter(filterGoogleTool) : [];
|
||||
|
|
|
|||
|
|
@ -712,6 +712,19 @@ const google: Record<string, SettingDefinition> = {
|
|||
showDefault: false,
|
||||
columnSpan: 2,
|
||||
},
|
||||
url_context: {
|
||||
key: 'url_context',
|
||||
label: 'com_endpoint_use_url_context',
|
||||
labelCode: true,
|
||||
description: 'com_endpoint_google_use_url_context',
|
||||
descriptionCode: true,
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
component: 'switch',
|
||||
optionType: 'model',
|
||||
showDefault: false,
|
||||
columnSpan: 2,
|
||||
},
|
||||
};
|
||||
|
||||
const googleConfig: SettingsConfiguration = [
|
||||
|
|
@ -727,6 +740,7 @@ const googleConfig: SettingsConfiguration = [
|
|||
google.thinkingBudget,
|
||||
google.thinkingLevel,
|
||||
google.web_search,
|
||||
google.url_context,
|
||||
librechat.fileTokenLimit,
|
||||
];
|
||||
|
||||
|
|
@ -747,6 +761,7 @@ const googleCol2: SettingsConfiguration = [
|
|||
google.thinkingBudget,
|
||||
google.thinkingLevel,
|
||||
google.web_search,
|
||||
google.url_context,
|
||||
librechat.fileTokenLimit,
|
||||
];
|
||||
|
||||
|
|
|
|||
|
|
@ -774,6 +774,8 @@ export const tConversationSchema = z.object({
|
|||
effort: eAnthropicEffortSchema.optional().nullable(),
|
||||
/* OpenAI Responses API / Anthropic API / Google API */
|
||||
web_search: z.boolean().optional(),
|
||||
/* Google API */
|
||||
url_context: z.boolean().optional(),
|
||||
/* disable streaming */
|
||||
disableStreaming: z.boolean().optional(),
|
||||
/* assistant */
|
||||
|
|
@ -882,6 +884,8 @@ export const tQueryParamsSchema = tConversationSchema
|
|||
useResponsesApi: true,
|
||||
/** @endpoints openAI, anthropic, google */
|
||||
web_search: true,
|
||||
/** @endpoints google */
|
||||
url_context: true,
|
||||
/** @endpoints openAI, custom, azureOpenAI */
|
||||
disableStreaming: true,
|
||||
/** @endpoints google, anthropic, bedrock */
|
||||
|
|
@ -996,6 +1000,7 @@ export const googleBaseSchema = tConversationSchema.pick({
|
|||
thinkingBudget: true,
|
||||
thinkingLevel: true,
|
||||
web_search: true,
|
||||
url_context: true,
|
||||
fileTokenLimit: true,
|
||||
iconURL: true,
|
||||
greeting: true,
|
||||
|
|
@ -1030,6 +1035,7 @@ export const googleGenConfigSchema = z
|
|||
})
|
||||
.optional(),
|
||||
web_search: z.boolean().optional(),
|
||||
url_context: z.boolean().optional(),
|
||||
})
|
||||
.strip()
|
||||
.optional();
|
||||
|
|
|
|||
|
|
@ -143,6 +143,10 @@ export const conversationPreset = {
|
|||
web_search: {
|
||||
type: Boolean,
|
||||
},
|
||||
/** Google API */
|
||||
url_context: {
|
||||
type: Boolean,
|
||||
},
|
||||
disableStreaming: {
|
||||
type: Boolean,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ export interface IPreset extends Document {
|
|||
verbosity?: string;
|
||||
useResponsesApi?: boolean;
|
||||
web_search?: boolean;
|
||||
url_context?: boolean;
|
||||
disableStreaming?: boolean;
|
||||
fileTokenLimit?: number;
|
||||
tenantId?: string;
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ export interface IConversation extends Document {
|
|||
verbosity?: string;
|
||||
useResponsesApi?: boolean;
|
||||
web_search?: boolean;
|
||||
url_context?: boolean;
|
||||
disableStreaming?: boolean;
|
||||
fileTokenLimit?: number;
|
||||
// Additional fields
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue