浏览代码

enh/refac: ability to specify external tool server id

Timothy Jaeryang Baek 1 月之前
父节点
当前提交
8a157578f4
共有 3 个文件被更改,包括 51 次插入15 次删除
  1. 3 3
      backend/open_webui/routers/tools.py
  2. 16 9
      backend/open_webui/utils/tools.py
  3. 32 3
      src/lib/components/AddServerModal.svelte

+ 3 - 3
backend/open_webui/routers/tools.py

@@ -54,8 +54,8 @@ async def get_tools(request: Request, user=Depends(get_verified_user)):
         tools.append(
         tools.append(
             ToolUserResponse(
             ToolUserResponse(
                 **{
                 **{
-                    "id": f"server:{server['idx']}",
-                    "user_id": f"server:{server['idx']}",
+                    "id": f"server:{server.get('id')}",
+                    "user_id": f"server:{server.get('id')}",
                     "name": server.get("openapi", {})
                     "name": server.get("openapi", {})
                     .get("info", {})
                     .get("info", {})
                     .get("title", "Tool Server"),
                     .get("title", "Tool Server"),
@@ -65,7 +65,7 @@ async def get_tools(request: Request, user=Depends(get_verified_user)):
                         .get("description", ""),
                         .get("description", ""),
                     },
                     },
                     "access_control": request.app.state.config.TOOL_SERVER_CONNECTIONS[
                     "access_control": request.app.state.config.TOOL_SERVER_CONNECTIONS[
-                        server["idx"]
+                        server.get("idx", 0)
                     ]
                     ]
                     .get("config", {})
                     .get("config", {})
                     .get("access_control", None),
                     .get("access_control", None),

+ 16 - 9
backend/open_webui/utils/tools.py

@@ -77,18 +77,22 @@ def get_tools(
         tool = Tools.get_tool_by_id(tool_id)
         tool = Tools.get_tool_by_id(tool_id)
         if tool is None:
         if tool is None:
             if tool_id.startswith("server:"):
             if tool_id.startswith("server:"):
-                server_idx = int(tool_id.split(":")[1])
-                tool_server_connection = (
-                    request.app.state.config.TOOL_SERVER_CONNECTIONS[server_idx]
-                )
+                server_id = tool_id.split(":")[1]
+
                 tool_server_data = None
                 tool_server_data = None
                 for server in request.app.state.TOOL_SERVERS:
                 for server in request.app.state.TOOL_SERVERS:
-                    if server["idx"] == server_idx:
+                    if server["id"] == server_id:
                         tool_server_data = server
                         tool_server_data = server
                         break
                         break
+
                 assert tool_server_data is not None
                 assert tool_server_data is not None
-                specs = tool_server_data.get("specs", [])
 
 
+                tool_server_idx = tool_server_data.get("idx", 0)
+                tool_server_connection = (
+                    request.app.state.config.TOOL_SERVER_CONNECTIONS[tool_server_idx]
+                )
+
+                specs = tool_server_data.get("specs", [])
                 for spec in specs:
                 for spec in specs:
                     function_name = spec["name"]
                     function_name = spec["name"]
 
 
@@ -506,11 +510,13 @@ async def get_tool_servers_data(
                 token = server.get("key", "")
                 token = server.get("key", "")
             elif auth_type == "session":
             elif auth_type == "session":
                 token = session_token
                 token = session_token
-            server_entries.append((idx, server, full_url, info, token))
+
+            id = info.get("id", idx)
+            server_entries.append((id, idx, server, full_url, info, token))
 
 
     # Create async tasks to fetch data
     # Create async tasks to fetch data
     tasks = [
     tasks = [
-        get_tool_server_data(token, url) for (_, _, url, _, token) in server_entries
+        get_tool_server_data(token, url) for (_, _, _, url, _, token) in server_entries
     ]
     ]
 
 
     # Execute tasks concurrently
     # Execute tasks concurrently
@@ -518,7 +524,7 @@ async def get_tool_servers_data(
 
 
     # Build final results with index and server metadata
     # Build final results with index and server metadata
     results = []
     results = []
-    for (idx, server, url, info, _), response in zip(server_entries, responses):
+    for (id, idx, server, url, info, _), response in zip(server_entries, responses):
         if isinstance(response, Exception):
         if isinstance(response, Exception):
             log.error(f"Failed to connect to {url} OpenAPI tool server")
             log.error(f"Failed to connect to {url} OpenAPI tool server")
             continue
             continue
@@ -536,6 +542,7 @@ async def get_tool_servers_data(
 
 
         results.append(
         results.append(
             {
             {
+                "id": str(id),
                 "idx": idx,
                 "idx": idx,
                 "url": server.get("url"),
                 "url": server.get("url"),
                 "openapi": openapi_data,
                 "openapi": openapi_data,

+ 32 - 3
src/lib/components/AddServerModal.svelte

@@ -35,6 +35,7 @@
 
 
 	let accessControl = {};
 	let accessControl = {};
 
 
+	let id = '';
 	let name = '';
 	let name = '';
 	let description = '';
 	let description = '';
 
 
@@ -76,6 +77,7 @@
 					access_control: accessControl
 					access_control: accessControl
 				},
 				},
 				info: {
 				info: {
+					id,
 					name,
 					name,
 					description
 					description
 				}
 				}
@@ -106,6 +108,7 @@
 				access_control: accessControl
 				access_control: accessControl
 			},
 			},
 			info: {
 			info: {
+				id: id,
 				name: name,
 				name: name,
 				description: description
 				description: description
 			}
 			}
@@ -121,6 +124,7 @@
 		key = '';
 		key = '';
 		auth_type = 'bearer';
 		auth_type = 'bearer';
 
 
+		id = '';
 		name = '';
 		name = '';
 		description = '';
 		description = '';
 
 
@@ -136,6 +140,7 @@
 			auth_type = connection?.auth_type ?? 'bearer';
 			auth_type = connection?.auth_type ?? 'bearer';
 			key = connection?.key ?? '';
 			key = connection?.key ?? '';
 
 
+			id = connection.info?.id ?? '';
 			name = connection.info?.name ?? '';
 			name = connection.info?.name ?? '';
 			description = connection.info?.description ?? '';
 			description = connection.info?.description ?? '';
 
 
@@ -306,12 +311,36 @@
 							<hr class=" border-gray-100 dark:border-gray-700/10 my-2.5 w-full" />
 							<hr class=" border-gray-100 dark:border-gray-700/10 my-2.5 w-full" />
 
 
 							<div class="flex gap-2">
 							<div class="flex gap-2">
+								<div class="flex flex-col w-full">
+									<label
+										for="enter-id"
+										class={`mb-0.5 text-xs ${($settings?.highContrastMode ?? false) ? 'text-gray-800 dark:text-gray-100' : 'text-gray-500'}`}
+										>{$i18n.t('ID')}
+										<span class="text-xs text-gray-200 dark:text-gray-800 ml-0.5"
+											>{$i18n.t('Optional')}</span
+										>
+									</label>
+
+									<div class="flex-1">
+										<input
+											id="enter-id"
+											class={`w-full text-sm bg-transparent ${($settings?.highContrastMode ?? false) ? 'placeholder:text-gray-700 dark:placeholder:text-gray-100' : 'outline-hidden placeholder:text-gray-300 dark:placeholder:text-gray-700'}`}
+											type="text"
+											bind:value={id}
+											placeholder={$i18n.t('Enter ID')}
+											autocomplete="off"
+										/>
+									</div>
+								</div>
+							</div>
+
+							<div class="flex gap-2 mt-2">
 								<div class="flex flex-col w-full">
 								<div class="flex flex-col w-full">
 									<label
 									<label
 										for="enter-name"
 										for="enter-name"
-										class={`mb-0.5 text-xs" ${($settings?.highContrastMode ?? false) ? 'text-gray-800 dark:text-gray-100' : 'text-gray-500'}`}
-										>{$i18n.t('Name')}</label
-									>
+										class={`mb-0.5 text-xs ${($settings?.highContrastMode ?? false) ? 'text-gray-800 dark:text-gray-100' : 'text-gray-500'}`}
+										>{$i18n.t('Name')}
+									</label>
 
 
 									<div class="flex-1">
 									<div class="flex-1">
 										<input
 										<input