mirror of
https://github.com/open-webui/open-webui
synced 2025-06-16 19:31:52 +00:00
enh: external tool server custom name/description support
This commit is contained in:
parent
20f54616e7
commit
a38e44e870
@ -51,11 +51,11 @@ async def get_tools(request: Request, user=Depends(get_verified_user)):
|
|||||||
**{
|
**{
|
||||||
"id": f"server:{server['idx']}",
|
"id": f"server:{server['idx']}",
|
||||||
"user_id": f"server:{server['idx']}",
|
"user_id": f"server:{server['idx']}",
|
||||||
"name": server["openapi"]
|
"name": server.get("openapi", {})
|
||||||
.get("info", {})
|
.get("info", {})
|
||||||
.get("title", "Tool Server"),
|
.get("title", "Tool Server"),
|
||||||
"meta": {
|
"meta": {
|
||||||
"description": server["openapi"]
|
"description": server.get("openapi", {})
|
||||||
.get("info", {})
|
.get("info", {})
|
||||||
.get("description", ""),
|
.get("description", ""),
|
||||||
},
|
},
|
||||||
|
@ -493,6 +493,8 @@ async def get_tool_servers_data(
|
|||||||
url_path = server.get("path", "openapi.json")
|
url_path = server.get("path", "openapi.json")
|
||||||
full_url = f"{server.get('url')}/{url_path}"
|
full_url = f"{server.get('url')}/{url_path}"
|
||||||
|
|
||||||
|
info = server.get("info", {})
|
||||||
|
|
||||||
auth_type = server.get("auth_type", "bearer")
|
auth_type = server.get("auth_type", "bearer")
|
||||||
token = None
|
token = None
|
||||||
|
|
||||||
@ -500,26 +502,37 @@ 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, token))
|
server_entries.append((idx, server, full_url, info, token))
|
||||||
|
|
||||||
# Create async tasks to fetch data
|
# Create async tasks to fetch data
|
||||||
tasks = [get_tool_server_data(token, url) for (_, _, url, token) in server_entries]
|
tasks = [
|
||||||
|
get_tool_server_data(token, url) for (_, _, url, _, token) in server_entries
|
||||||
|
]
|
||||||
|
|
||||||
# Execute tasks concurrently
|
# Execute tasks concurrently
|
||||||
responses = await asyncio.gather(*tasks, return_exceptions=True)
|
responses = await asyncio.gather(*tasks, return_exceptions=True)
|
||||||
|
|
||||||
# Build final results with index and server metadata
|
# Build final results with index and server metadata
|
||||||
results = []
|
results = []
|
||||||
for (idx, server, url, _), response in zip(server_entries, responses):
|
for (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
|
||||||
|
|
||||||
|
openapi_data = response.get("openapi", {})
|
||||||
|
|
||||||
|
if info and isinstance(openapi_data, dict):
|
||||||
|
if "name" in info:
|
||||||
|
openapi_data["info"]["title"] = info.get("name", "Tool Server")
|
||||||
|
|
||||||
|
if "description" in info:
|
||||||
|
openapi_data["info"]["description"] = info.get("description", "")
|
||||||
|
|
||||||
results.append(
|
results.append(
|
||||||
{
|
{
|
||||||
"idx": idx,
|
"idx": idx,
|
||||||
"url": server.get("url"),
|
"url": server.get("url"),
|
||||||
"openapi": response.get("openapi"),
|
"openapi": openapi_data,
|
||||||
"info": response.get("info"),
|
"info": response.get("info"),
|
||||||
"specs": response.get("specs"),
|
"specs": response.get("specs"),
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,6 @@
|
|||||||
export let edit = false;
|
export let edit = false;
|
||||||
|
|
||||||
export let direct = false;
|
export let direct = false;
|
||||||
|
|
||||||
export let connection = null;
|
export let connection = null;
|
||||||
|
|
||||||
let url = '';
|
let url = '';
|
||||||
@ -33,6 +32,9 @@
|
|||||||
|
|
||||||
let accessControl = {};
|
let accessControl = {};
|
||||||
|
|
||||||
|
let name = '';
|
||||||
|
let description = '';
|
||||||
|
|
||||||
let enable = true;
|
let enable = true;
|
||||||
|
|
||||||
let loading = false;
|
let loading = false;
|
||||||
@ -69,6 +71,10 @@
|
|||||||
config: {
|
config: {
|
||||||
enable: enable,
|
enable: enable,
|
||||||
access_control: accessControl
|
access_control: accessControl
|
||||||
|
},
|
||||||
|
info: {
|
||||||
|
name,
|
||||||
|
description
|
||||||
}
|
}
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
toast.error($i18n.t('Connection failed'));
|
toast.error($i18n.t('Connection failed'));
|
||||||
@ -95,6 +101,10 @@
|
|||||||
config: {
|
config: {
|
||||||
enable: enable,
|
enable: enable,
|
||||||
access_control: accessControl
|
access_control: accessControl
|
||||||
|
},
|
||||||
|
info: {
|
||||||
|
name: name,
|
||||||
|
description: description
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -108,6 +118,9 @@
|
|||||||
key = '';
|
key = '';
|
||||||
auth_type = 'bearer';
|
auth_type = 'bearer';
|
||||||
|
|
||||||
|
name = '';
|
||||||
|
description = '';
|
||||||
|
|
||||||
enable = true;
|
enable = true;
|
||||||
accessControl = null;
|
accessControl = null;
|
||||||
};
|
};
|
||||||
@ -120,6 +133,9 @@
|
|||||||
auth_type = connection?.auth_type ?? 'bearer';
|
auth_type = connection?.auth_type ?? 'bearer';
|
||||||
key = connection?.key ?? '';
|
key = connection?.key ?? '';
|
||||||
|
|
||||||
|
name = connection.info?.name ?? '';
|
||||||
|
description = connection.info?.description ?? '';
|
||||||
|
|
||||||
enable = connection.config?.enable ?? true;
|
enable = connection.config?.enable ?? true;
|
||||||
accessControl = connection.config?.access_control ?? null;
|
accessControl = connection.config?.access_control ?? null;
|
||||||
}
|
}
|
||||||
@ -276,6 +292,39 @@
|
|||||||
{#if !direct}
|
{#if !direct}
|
||||||
<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 flex-col w-full">
|
||||||
|
<div class=" mb-0.5 text-xs text-gray-500">{$i18n.t('Name')}</div>
|
||||||
|
|
||||||
|
<div class="flex-1">
|
||||||
|
<input
|
||||||
|
class="w-full text-sm bg-transparent placeholder:text-gray-300 dark:placeholder:text-gray-700 outline-hidden"
|
||||||
|
type="text"
|
||||||
|
bind:value={name}
|
||||||
|
placeholder={$i18n.t('Enter name')}
|
||||||
|
autocomplete="off"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-col w-full mt-2">
|
||||||
|
<div class=" mb-1 text-xs text-gray-500">{$i18n.t('Description')}</div>
|
||||||
|
|
||||||
|
<div class="flex-1">
|
||||||
|
<input
|
||||||
|
class="w-full text-sm bg-transparent placeholder:text-gray-300 dark:placeholder:text-gray-700 outline-hidden"
|
||||||
|
type="text"
|
||||||
|
bind:value={description}
|
||||||
|
placeholder={$i18n.t('Enter description')}
|
||||||
|
autocomplete="off"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr class=" border-gray-100 dark:border-gray-700/10 my-2.5 w-full" />
|
||||||
|
|
||||||
<div class="my-2 -mx-2">
|
<div class="my-2 -mx-2">
|
||||||
<div class="px-3 py-2 bg-gray-50 dark:bg-gray-950 rounded-lg">
|
<div class="px-3 py-2 bg-gray-50 dark:bg-gray-950 rounded-lg">
|
||||||
<AccessControl bind:accessControl />
|
<AccessControl bind:accessControl />
|
||||||
|
Loading…
Reference in New Issue
Block a user