fix: enforce global web search and image generation switches on the legacy function-calling path (#27669)

The legacy function-calling path acted on the client-supplied `features` dict after checking only the per-user permission, so a user who still held `features.web_search` or `features.image_generation` could keep triggering web searches and image generation after an administrator had switched those off instance-wide. The native function-calling path already gates the equivalent builtin tools on `web.search.enable` and `image_generation.enable` in `get_builtin_tools`, so the two paths disagreed and the admin-level switch did not actually stop the outbound provider calls it was turned off to stop.

Gate the legacy web search handler on `web.search.enable` at its call site, and gate `chat_image_generation_handler` on the two image switches internally. The image handler needs the check inside it because `image_generation.enable` and `images.edit.enable` are independent: editing stays available when generation is disabled, matching the `/images/generations` and `/images/edit` routes and the native `generate_image`/`edit_image` tools. The handler calls `image_generations`/`image_edits` directly and so bypasses the route guards, which is why the check has to live at the caller.

The "Creating image" status event moves below the new guard so a disabled configuration returns without leaving an unresolved progress indicator in the chat.
This commit is contained in:
Classic298
2026-08-17 02:15:05 -06:00
committed by GitHub
parent 7ea46a37d0
commit 646a568ae6
+15 -8
View File
@@ -1666,12 +1666,6 @@ async def chat_image_generation_handler(request: Request, form_data: dict, extra
message_list = form_data.get('messages', [])
else:
chat = await Chats.get_chat_by_id_and_user_id(chat_id, user.id)
await __event_emitter__(
{
'type': 'status',
'data': {'description': 'Creating image', 'done': False},
}
)
messages_map = chat.chat.get('history', {}).get('messages', {})
message_id = chat.chat.get('history', {}).get('currentId')
@@ -1691,9 +1685,22 @@ async def chat_image_generation_handler(request: Request, form_data: dict, extra
for image in images:
input_images.append(image)
# Called directly, bypassing the /images routes that enforce these switches.
editing = len(input_images) > 0 and await Config.get('images.edit.enable')
if not editing and not await Config.get('image_generation.enable'):
return form_data
if is_saved_chat_id(chat_id):
await __event_emitter__(
{
'type': 'status',
'data': {'description': 'Creating image', 'done': False},
}
)
system_message_content = ''
if len(input_images) > 0 and await Config.get('images.edit.enable'):
if editing:
# Edit image(s)
try:
images = await image_edits(
@@ -2527,7 +2534,7 @@ async def process_chat_payload(request, form_data, user, metadata, model):
):
form_data = await add_memory_context(request, form_data, user, model)
if 'web_search' in features and features['web_search']:
if 'web_search' in features and features['web_search'] and await Config.get('web.search.enable'):
# features is client-supplied; re-check the permission the native FC path enforces.
if getattr(user, 'role', None) == 'admin' or await has_permission(
getattr(user, 'id', ''),