diff --git a/backend/open_webui/routers/configs.py b/backend/open_webui/routers/configs.py index 1a0608ea51..cf0ebdeb82 100644 --- a/backend/open_webui/routers/configs.py +++ b/backend/open_webui/routers/configs.py @@ -769,6 +769,7 @@ class ModelsConfigForm(BaseModel): async def get_models_defaults(request: Request, user=Depends(get_verified_user)): return { 'DEFAULT_MODEL_METADATA': await Config.get('models.default_metadata'), + 'DEFAULT_FUNCTION_CALLING': (await Config.get('models.default_params') or {}).get('function_calling'), } diff --git a/backend/open_webui/utils/middleware.py b/backend/open_webui/utils/middleware.py index dc771047c4..44a9e676b8 100644 --- a/backend/open_webui/utils/middleware.py +++ b/backend/open_webui/utils/middleware.py @@ -172,6 +172,7 @@ from open_webui.utils.tools import ( get_terminal_tools, get_tools, get_updated_tool_function, + is_file_context_enabled, ) from starlette.responses import JSONResponse, Response, StreamingResponse @@ -2889,8 +2890,7 @@ async def process_chat_payload(request, form_data, user, metadata, model): except Exception as e: log.exception(e) - # Check if file context extraction is enabled for this model (default True) - file_context_enabled = (model.get('info', {}).get('meta', {}).get('capabilities') or {}).get('file_context', True) + file_context_enabled = is_file_context_enabled(model, metadata) if file_context_enabled: try: diff --git a/backend/open_webui/utils/tools.py b/backend/open_webui/utils/tools.py index 09c1a7bbf1..23cbcaea00 100644 --- a/backend/open_webui/utils/tools.py +++ b/backend/open_webui/utils/tools.py @@ -585,6 +585,12 @@ async def get_tools(request: Request, tool_ids: list[str], user: UserModel, extr return tools_dict +def is_file_context_enabled(model: dict, metadata: dict) -> bool: + return (model.get('info', {}).get('meta', {}).get('capabilities') or {}).get( + 'file_context', metadata.get('params', {}).get('function_calling') == 'legacy' + ) + + def get_attached_knowledge(model: dict, metadata: dict) -> list[dict]: model_meta = model.get('info', {}).get('meta', {}) knowledge = [] @@ -603,8 +609,7 @@ def get_attached_knowledge(model: dict, metadata: dict) -> list[dict]: knowledge.append({**item, 'source': source}) seen.add(key) - file_context_enabled = (model_meta.get('capabilities') or {}).get('file_context', True) - if not file_context_enabled: + if not is_file_context_enabled(model, metadata): for item in metadata.get('files') or []: if not isinstance(item, dict) or item.get('type') not in ('collection', 'note'): continue @@ -736,7 +741,7 @@ async def get_builtin_tools( if ( is_builtin_tool_enabled('files') and get_model_capability('file_upload') - and not get_model_capability('file_context') + and not is_file_context_enabled(model, metadata) and has_chat_files and await has_user_chat_permission('file_upload') ): diff --git a/src/lib/components/admin/Settings/Models/ModelDefaultsPanel.svelte b/src/lib/components/admin/Settings/Models/ModelDefaultsPanel.svelte index 9de03688c3..f02fd30b3f 100644 --- a/src/lib/components/admin/Settings/Models/ModelDefaultsPanel.svelte +++ b/src/lib/components/admin/Settings/Models/ModelDefaultsPanel.svelte @@ -83,7 +83,7 @@ const savedMeta = config?.DEFAULT_MODEL_METADATA; if (savedMeta && Object.keys(savedMeta).length > 0) { - defaultCapabilities = savedMeta.capabilities ?? { ...DEFAULT_CAPABILITIES }; + defaultCapabilities = { ...DEFAULT_CAPABILITIES, ...(savedMeta.capabilities ?? {}) }; defaultFeatureIds = savedMeta.defaultFeatureIds ?? []; builtinTools = savedMeta.builtinTools ?? {}; toolIds = savedMeta.toolIds ?? []; @@ -215,6 +215,7 @@ > diff --git a/src/lib/components/workspace/Models/Capabilities.svelte b/src/lib/components/workspace/Models/Capabilities.svelte index 3b0d07fcc7..7b06624b15 100644 --- a/src/lib/components/workspace/Models/Capabilities.svelte +++ b/src/lib/components/workspace/Models/Capabilities.svelte @@ -68,6 +68,11 @@ type Capability = keyof typeof capabilityLabels; export let capabilities: Partial> = {}; + export let functionCalling: string | null = null; + $: effectiveCapabilities = { + ...capabilities, + file_context: capabilities.file_context ?? functionCalling === 'legacy' + }; export let defaultFeatureIds: string[] = []; export let builtinTools: Record = {}; @@ -81,7 +86,7 @@ (key !== 'terminal' || hasTerminal) && (capabilityLabels[key].enabled ?? true) ); - $: enabledCapabilityIds = availableCapabilities.filter((key) => capabilities[key]); + $: enabledCapabilityIds = availableCapabilities.filter((key) => effectiveCapabilities[key]); $: availableFeatures = featureKeys.filter((key) => enabledCapabilityIds.includes(key)); $: enabledDefaultIds = availableFeatures.filter((key) => defaultFeatureIds.includes(key)); const setDefault = (key: string, enabled: boolean) => { @@ -114,7 +119,8 @@ (capabilities[key] = e.detail)} {disabled} /> {/each} diff --git a/src/lib/components/workspace/Models/ModelEditor.svelte b/src/lib/components/workspace/Models/ModelEditor.svelte index 1c2bc33b08..75e658b3d3 100644 --- a/src/lib/components/workspace/Models/ModelEditor.svelte +++ b/src/lib/components/workspace/Models/ModelEditor.svelte @@ -94,6 +94,7 @@ let commitMessage = ''; let savedDraft = ''; let defaultMeta: Record = {}; + let defaultFunctionCalling: string | null = null; let allowNavigation = false; let showDiscard = false; let afterDiscard: (() => void) | null = null; @@ -784,6 +785,7 @@ // reflects the actual defaults rather than hardcoded values const modelsConfig = await getModelsDefaults(localStorage.token).catch(() => null); defaultMeta = modelsConfig?.DEFAULT_MODEL_METADATA ?? {}; + defaultFunctionCalling = modelsConfig?.DEFAULT_FUNCTION_CALLING ?? null; // Use admin defaults as base, falling back to hardcoded defaults capabilities = { ...DEFAULT_CAPABILITIES, ...(defaultMeta.capabilities ?? {}) }; @@ -1723,6 +1725,7 @@