From 969669b6471d5e9baa97a25cb2e6df3748ae71ea Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Fri, 24 Jul 2026 09:27:24 +0200 Subject: [PATCH] refac: fetch the terminal system prompt per request without a cache Drop the module-level TTL cache and fetch the system prompt directly in get_terminal_tools, gathered with the existing uncached per-request cwd fetch that already follows this pattern. The fetch uses the user's own credentials and falls back to the set_terminal_servers snapshot, so a cold or unreachable instance degrades to the previous behaviour instead of needing an error cache. Also restore the 3s timeout: on the request path a 30s wait would stall chat completions, and a cold instance is covered by the snapshot fallback until it warms up. --- backend/open_webui/utils/tools.py | 42 +++---------------------------- 1 file changed, 3 insertions(+), 39 deletions(-) diff --git a/backend/open_webui/utils/tools.py b/backend/open_webui/utils/tools.py index de9b97ca60..0c55805c9e 100644 --- a/backend/open_webui/utils/tools.py +++ b/backend/open_webui/utils/tools.py @@ -8,7 +8,6 @@ import json import logging import os import re -import time from functools import partial, update_wrapper from typing import ( Any, @@ -1094,8 +1093,7 @@ async def get_terminal_system_prompt( base = base_url.rstrip('/') try: async with aiohttp.ClientSession( - # 30s: orchestrator instances may cold-start before answering - timeout=aiohttp.ClientTimeout(total=30), + timeout=aiohttp.ClientTimeout(total=3), trust_env=True, ) as session: # 1. Check feature flag @@ -1120,39 +1118,6 @@ async def get_terminal_system_prompt( return None -_TERMINAL_SYSTEM_PROMPT_TTL = 300 # seconds -_TERMINAL_SYSTEM_PROMPT_ERROR_TTL = 60 # seconds -_terminal_system_prompt_cache: dict[tuple[str, str], tuple[float, str | None]] = {} - - -async def get_cached_terminal_system_prompt( - base_url: str, - headers: dict, - cookies: dict | None = None, -) -> str | None: - """Return a terminal server's system prompt, cached per (URL, user). - - Each user may resolve to a different orchestrator instance. Failures - are cached briefly so an unreachable instance doesn't stall every - request. - """ - key = (base_url, headers.get('X-User-Id', '')) - now = time.monotonic() - - cached = _terminal_system_prompt_cache.get(key) - if cached and cached[0] > now: - return cached[1] - - prompt = await get_terminal_system_prompt(base_url, headers, cookies) - - if len(_terminal_system_prompt_cache) > 4096: - for stale_key in [k for k, (expiry, _) in _terminal_system_prompt_cache.items() if expiry <= now]: - _terminal_system_prompt_cache.pop(stale_key, None) - ttl = _TERMINAL_SYSTEM_PROMPT_TTL if prompt else _TERMINAL_SYSTEM_PROMPT_ERROR_TTL - _terminal_system_prompt_cache[key] = (now + ttl, prompt) - return prompt - - async def set_terminal_servers(request: Request): """Load and cache OpenAPI specs from all TERMINAL_SERVER_CONNECTIONS.""" connections = await Config.get('terminal_server.connections', []) or [] @@ -1286,11 +1251,10 @@ async def get_terminal_tools( if session_id: headers['X-Session-Id'] = session_id - # Live fetch with the user's credentials; the set_terminal_servers - # snapshot is the fallback. + # Fetch live with the user's credentials so prompt changes apply without a restart terminal_cwd, system_prompt = await asyncio.gather( get_terminal_cwd(server_data['url'], headers, cookies), - get_cached_terminal_system_prompt(server_data['url'], headers, cookies), + get_terminal_system_prompt(server_data['url'], headers, cookies), ) if not system_prompt: system_prompt = server_data.get('system_prompt')