From 2e20018a9eaecea279ea4e2765a809e243bb9433 Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Thu, 2 Apr 2026 15:23:06 +0200 Subject: [PATCH] Add direct server connection support --- backend/open_webui/tools/builtin.py | 69 +++++++++++++++++------------ 1 file changed, 41 insertions(+), 28 deletions(-) diff --git a/backend/open_webui/tools/builtin.py b/backend/open_webui/tools/builtin.py index f0d6a0308c..8af9b52bf7 100644 --- a/backend/open_webui/tools/builtin.py +++ b/backend/open_webui/tools/builtin.py @@ -2883,39 +2883,52 @@ async def upload_file_to_terminal( # --- 2. Resolve terminal connection and build auth --- from open_webui.utils.access_control import has_connection_access + terminal_url = None + cookies = {} + headers = {'X-User-Id': __user__.get('id', '')} + + # Try system terminal first (terminal_id is a connection ID) connections = __request__.app.state.config.TERMINAL_SERVER_CONNECTIONS or [] connection = next( (c for c in connections if c.get('id') == terminal_id), None ) - if not connection: - return json.dumps({'error': f"Terminal connection '{terminal_id}' not found"}) - if not has_connection_access(UserModel(**__user__), connection): - return json.dumps({'error': 'Access denied to terminal server'}) + if connection: + if not has_connection_access(UserModel(**__user__), connection): + return json.dumps({'error': 'Access denied to terminal server'}) + + terminal_url = connection.get('url', '').rstrip('/') + + # Build auth headers/cookies matching resolve_terminal_tools pattern + auth_type = connection.get('auth_type', 'bearer') + if auth_type == 'bearer': + key = connection.get('key', '') + if key: + headers['Authorization'] = f'Bearer {key}' + elif auth_type == 'session': + cookies = __request__.cookies + if hasattr(__request__, 'state') and hasattr(__request__.state, 'token'): + headers['Authorization'] = f'Bearer {__request__.state.token.credentials}' + elif auth_type == 'system_oauth': + cookies = __request__.cookies + oauth_token = (metadata.get('oauth_token') or {}) + if oauth_token.get('access_token'): + headers['Authorization'] = f'Bearer {oauth_token["access_token"]}' + # auth_type == 'none': no Authorization header + else: + # Try direct/user-configured terminal (terminal_id is the URL) + direct_tool_servers = metadata.get('tool_servers') or [] + for ts in direct_tool_servers: + ts_url = (ts.get('url') or '').rstrip('/') + if ts_url and ts_url == terminal_id.rstrip('/'): + terminal_url = ts_url + key = ts.get('key', '') + if key: + headers['Authorization'] = f'Bearer {key}' + break - terminal_url = connection.get('url', '').rstrip('/') if not terminal_url: - return json.dumps({'error': 'Terminal connection has no URL configured'}) - - # Build auth headers/cookies matching resolve_terminal_tools pattern - auth_type = connection.get('auth_type', 'bearer') - cookies = {} - headers = {'X-User-Id': __user__.get('id', '')} - - if auth_type == 'bearer': - key = connection.get('key', '') - if key: - headers['Authorization'] = f'Bearer {key}' - elif auth_type == 'session': - cookies = __request__.cookies - if hasattr(__request__, 'state') and hasattr(__request__.state, 'token'): - headers['Authorization'] = f'Bearer {__request__.state.token.credentials}' - elif auth_type == 'system_oauth': - cookies = __request__.cookies - oauth_token = (metadata.get('oauth_token') or {}) - if oauth_token.get('access_token'): - headers['Authorization'] = f'Bearer {oauth_token["access_token"]}' - # auth_type == 'none': no Authorization header + return json.dumps({'error': f"Terminal connection '{terminal_id}' could not be resolved"}) chat_id = metadata.get('chat_id') if chat_id: @@ -2939,8 +2952,8 @@ async def upload_file_to_terminal( if cwd_resp.status == 200: data = await cwd_resp.json() upload_dir = data.get('cwd', '.') - except Exception: - pass + except Exception as e: + log.warning(f'upload_file_to_terminal: failed to fetch CWD, defaulting to ".": {e}') log.info( f"upload_file_to_terminal: uploading '{file_record.filename}' "