From 5b1c42e81a3ef3ad5ce5852dbf84020cb5e2498c Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Mon, 29 Jun 2026 00:05:10 -0500 Subject: [PATCH] refac --- backend/open_webui/config.py | 3 +++ backend/open_webui/utils/automations.py | 26 +++++++++++++++++++++---- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/backend/open_webui/config.py b/backend/open_webui/config.py index 5455d834c8..940e7053b1 100644 --- a/backend/open_webui/config.py +++ b/backend/open_webui/config.py @@ -1894,6 +1894,8 @@ AUTOMATION_MAX_COUNT = os.getenv('AUTOMATION_MAX_COUNT', '') AUTOMATION_MIN_INTERVAL = os.getenv('AUTOMATION_MIN_INTERVAL', '') +AUTOMATION_AUTH_TOKEN_EXPIRES_IN = os.getenv('AUTOMATION_AUTH_TOKEN_EXPIRES_IN', '1h') + ENABLE_NOTES = os.getenv('ENABLE_NOTES', 'True').lower() == 'true' ENABLE_USER_STATUS = os.getenv('ENABLE_USER_STATUS', 'True').lower() == 'true' @@ -2898,6 +2900,7 @@ DEFAULT_CONFIG = { 'automations.enable': ENABLE_AUTOMATIONS, 'automations.max_count': AUTOMATION_MAX_COUNT, 'automations.min_interval': AUTOMATION_MIN_INTERVAL, + 'automations.auth_token_expires_in': AUTOMATION_AUTH_TOKEN_EXPIRES_IN, 'notes.enable': ENABLE_NOTES, 'users.enable_status': ENABLE_USER_STATUS, 'evaluation.arena.enable': ENABLE_EVALUATION_ARENA_MODELS, diff --git a/backend/open_webui/utils/automations.py b/backend/open_webui/utils/automations.py index 60c359db1e..c826dd5742 100644 --- a/backend/open_webui/utils/automations.py +++ b/backend/open_webui/utils/automations.py @@ -18,13 +18,14 @@ import logging import os import random import time -from datetime import datetime +from datetime import datetime, timedelta from typing import Optional from uuid import uuid4 from zoneinfo import ZoneInfo from dateutil.rrule import rrulestr from fastapi import Request +from fastapi.security import HTTPAuthorizationCredentials from open_webui.constants import ERROR_MESSAGES from open_webui.events import EVENTS, publish_event from open_webui.internal.db import get_async_db @@ -32,6 +33,8 @@ from open_webui.models.automations import AutomationModel, AutomationRuns, Autom from open_webui.models.chats import ChatForm, Chats from open_webui.models.config import Config from open_webui.models.users import Users +from open_webui.utils.auth import create_token +from open_webui.utils.misc import parse_duration from open_webui.utils.task import prompt_template from starlette.datastructures import Headers @@ -204,11 +207,18 @@ async def scheduler_worker_loop(app) -> None: #################### -def _build_request(app) -> Request: +def _build_request( + app, + token: Optional[str] = None, +) -> Request: """Build a minimal ASGI Request for chat_completion. Mirrors the mock-request pattern used in main.py lifespan (model pre-fetch, tool server init) for consistency. + + When token is provided, attach it as + request.state.token so session-auth tool servers and terminals can + authenticate headless scheduled runs as the automation owner. """ scope = { 'type': 'http', @@ -224,7 +234,7 @@ def _build_request(app) -> Request: } request = Request(scope) # Ensure request.state is initialized with required attributes - request.state.token = None + request.state.token = HTTPAuthorizationCredentials(scheme='Bearer', credentials=token) if token else None request.state.enable_api_keys = False return request @@ -493,7 +503,15 @@ async def execute_automation(app, automation: AutomationModel) -> None: # Call the full chat completion pipeline (same as POST /api/chat/completions). # The handler reference is stored on app.state to avoid circular imports. - request = _build_request(app) + try: + expires_delta = parse_duration(str(await Config.get('automations.auth_token_expires_in', '1h'))) + except ValueError: + expires_delta = None + token = create_token( + data={'id': user.id, 'typ': 'automation'}, + expires_delta=expires_delta or timedelta(hours=1), + ) + request = _build_request(app, token=token) await app.state.CHAT_COMPLETION_HANDLER(request, form_data, user=user) # Notify user