enh: external tool server custom name/description support

This commit is contained in:
Timothy Jaeryang Baek 2025-05-27 00:10:33 +04:00
parent 20f54616e7
commit a38e44e870
3 changed files with 69 additions and 7 deletions

View File

@ -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", ""),
}, },

View File

@ -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"),
} }

View File

@ -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 />