+110









Yeuoly
GitHub
takatost
kurokobo
Novice Lee
zxhlyh
AkaraChen
Yi
Joel
JzoNg
twwu
Hiroshi Fujita
AkaraChen
NFish
Wu Tianwei
非法操作
Novice
Hiroki Nagai
Gen Sato
eux
huangzhuo1949
huangzhuo
lotsik
crazywoola
nite-knite
Jyong
github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
gakkiyomi
CN-P5
CN-P5
Chuehnone
yihong
Kevin9703
-LAN-
Boris Feld
mbo
mabo
Warren Chen
JzoNgKVO
jiandanfeng
zhu-an
zhaoqingyu.1075
海狸大師
Xu Song
rayshaw001
Ding Jiatong
Bowen Liang
JasonVV
le0zh
zhuxinliang
k-zaku
luckylhb90
hobo.l
jiangbo721
刘江波
Shun Miyazawa
EricPan
crazywoola
sino
Jhvcc
lowell
Boris Polonsky
Ademílson Tonato
Ademílson Tonato
IWAI, Masaharu <[email protected]>
Yueh-Po Peng
Jason
Xin Zhang
yjc980121
heyszt
Abdullah AlOsaimi
Abdullah AlOsaimi
Yingchun Lai
Hash Brown
zuodongxu
Masashi Tomooka
aplio
Obada Khalili
Nam Vu
Kei YAMAZAKI
TechnoHouse
Riddhimaan-Senapati
MaFee921
te-chan
HQidea
Joshbly
xhe
weiwenyan-dev
ex_wenyan.wei
engchina
engchina
dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
呆萌闷油瓶
Kemal
Lazy_Frog
Yi Xiao
Steven sun
steven
Kalo Chin
Katy Tao
depy
胡春东
Junjie.M
MuYu
Naoki Takashima
Summer-Gu
Fei He
ybalbert001
Yuanbo Li
douxc
liuzhenghua
Wu Jiayang
Your Name
kimjion
AugNSo
llinvokerl
liusurong.lsr
Vasu Negi
Hundredwz
Xiyuan Chen
403e2d58b9
Signed-off-by: yihong0618 <[email protected]> Signed-off-by: -LAN- <[email protected]> Signed-off-by: xhe <[email protected]> Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: takatost <[email protected]> Co-authored-by: kurokobo <[email protected]> Co-authored-by: Novice Lee <[email protected]> Co-authored-by: zxhlyh <[email protected]> Co-authored-by: AkaraChen <[email protected]> Co-authored-by: Yi <[email protected]> Co-authored-by: Joel <[email protected]> Co-authored-by: JzoNg <[email protected]> Co-authored-by: twwu <[email protected]> Co-authored-by: Hiroshi Fujita <[email protected]> Co-authored-by: AkaraChen <[email protected]> Co-authored-by: NFish <[email protected]> Co-authored-by: Wu Tianwei <[email protected]> Co-authored-by: 非法操作 <[email protected]> Co-authored-by: Novice <[email protected]> Co-authored-by: Hiroki Nagai <[email protected]> Co-authored-by: Gen Sato <[email protected]> Co-authored-by: eux <[email protected]> Co-authored-by: huangzhuo1949 <[email protected]> Co-authored-by: huangzhuo <[email protected]> Co-authored-by: lotsik <[email protected]> Co-authored-by: crazywoola <[email protected]> Co-authored-by: nite-knite <[email protected]> Co-authored-by: Jyong <[email protected]> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: gakkiyomi <[email protected]> Co-authored-by: CN-P5 <[email protected]> Co-authored-by: CN-P5 <[email protected]> Co-authored-by: Chuehnone <[email protected]> Co-authored-by: yihong <[email protected]> Co-authored-by: Kevin9703 <[email protected]> Co-authored-by: -LAN- <[email protected]> Co-authored-by: Boris Feld <[email protected]> Co-authored-by: mbo <[email protected]> Co-authored-by: mabo <[email protected]> Co-authored-by: Warren Chen <[email protected]> Co-authored-by: JzoNgKVO <[email protected]> Co-authored-by: jiandanfeng <[email protected]> Co-authored-by: zhu-an <[email protected]> Co-authored-by: zhaoqingyu.1075 <[email protected]> Co-authored-by: 海狸大師 <[email protected]> Co-authored-by: Xu Song <[email protected]> Co-authored-by: rayshaw001 <[email protected]> Co-authored-by: Ding Jiatong <[email protected]> Co-authored-by: Bowen Liang <[email protected]> Co-authored-by: JasonVV <[email protected]> Co-authored-by: le0zh <[email protected]> Co-authored-by: zhuxinliang <[email protected]> Co-authored-by: k-zaku <[email protected]> Co-authored-by: luckylhb90 <[email protected]> Co-authored-by: hobo.l <[email protected]> Co-authored-by: jiangbo721 <[email protected]> Co-authored-by: 刘江波 <[email protected]> Co-authored-by: Shun Miyazawa <[email protected]> Co-authored-by: EricPan <[email protected]> Co-authored-by: crazywoola <[email protected]> Co-authored-by: sino <[email protected]> Co-authored-by: Jhvcc <[email protected]> Co-authored-by: lowell <[email protected]> Co-authored-by: Boris Polonsky <[email protected]> Co-authored-by: Ademílson Tonato <[email protected]> Co-authored-by: Ademílson Tonato <[email protected]> Co-authored-by: IWAI, Masaharu <[email protected]> Co-authored-by: Yueh-Po Peng (Yabi) <[email protected]> Co-authored-by: Jason <[email protected]> Co-authored-by: Xin Zhang <[email protected]> Co-authored-by: yjc980121 <[email protected]> Co-authored-by: heyszt <[email protected]> Co-authored-by: Abdullah AlOsaimi <[email protected]> Co-authored-by: Abdullah AlOsaimi <[email protected]> Co-authored-by: Yingchun Lai <[email protected]> Co-authored-by: Hash Brown <[email protected]> Co-authored-by: zuodongxu <[email protected]> Co-authored-by: Masashi Tomooka <[email protected]> Co-authored-by: aplio <[email protected]> Co-authored-by: Obada Khalili <[email protected]> Co-authored-by: Nam Vu <[email protected]> Co-authored-by: Kei YAMAZAKI <[email protected]> Co-authored-by: TechnoHouse <[email protected]> Co-authored-by: Riddhimaan-Senapati <[email protected]> Co-authored-by: MaFee921 <[email protected]> Co-authored-by: te-chan <[email protected]> Co-authored-by: HQidea <[email protected]> Co-authored-by: Joshbly <[email protected]> Co-authored-by: xhe <[email protected]> Co-authored-by: weiwenyan-dev <[email protected]> Co-authored-by: ex_wenyan.wei <[email protected]> Co-authored-by: engchina <[email protected]> Co-authored-by: engchina <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: 呆萌闷油瓶 <[email protected]> Co-authored-by: Kemal <[email protected]> Co-authored-by: Lazy_Frog <[email protected]> Co-authored-by: Yi Xiao <[email protected]> Co-authored-by: Steven sun <[email protected]> Co-authored-by: steven <[email protected]> Co-authored-by: Kalo Chin <[email protected]> Co-authored-by: Katy Tao <[email protected]> Co-authored-by: depy <[email protected]> Co-authored-by: 胡春东 <[email protected]> Co-authored-by: Junjie.M <[email protected]> Co-authored-by: MuYu <[email protected]> Co-authored-by: Naoki Takashima <[email protected]> Co-authored-by: Summer-Gu <[email protected]> Co-authored-by: Fei He <[email protected]> Co-authored-by: ybalbert001 <[email protected]> Co-authored-by: Yuanbo Li <[email protected]> Co-authored-by: douxc <[email protected]> Co-authored-by: liuzhenghua <[email protected]> Co-authored-by: Wu Jiayang <[email protected]> Co-authored-by: Your Name <[email protected]> Co-authored-by: kimjion <[email protected]> Co-authored-by: AugNSo <[email protected]> Co-authored-by: llinvokerl <[email protected]> Co-authored-by: liusurong.lsr <[email protected]> Co-authored-by: Vasu Negi <[email protected]> Co-authored-by: Hundredwz <[email protected]> Co-authored-by: Xiyuan Chen <[email protected]>
484 lines
18 KiB
Python
484 lines
18 KiB
Python
import json
|
|
import logging
|
|
from collections.abc import Mapping
|
|
from typing import Any, cast
|
|
|
|
from httpx import get
|
|
|
|
from core.entities.provider_entities import ProviderConfig
|
|
from core.model_runtime.utils.encoders import jsonable_encoder
|
|
from core.tools.__base.tool_runtime import ToolRuntime
|
|
from core.tools.custom_tool.provider import ApiToolProviderController
|
|
from core.tools.entities.api_entities import ToolApiEntity, ToolProviderApiEntity
|
|
from core.tools.entities.common_entities import I18nObject
|
|
from core.tools.entities.tool_bundle import ApiToolBundle
|
|
from core.tools.entities.tool_entities import (
|
|
ApiProviderAuthType,
|
|
ApiProviderSchemaType,
|
|
)
|
|
from core.tools.tool_label_manager import ToolLabelManager
|
|
from core.tools.tool_manager import ToolManager
|
|
from core.tools.utils.configuration import ProviderConfigEncrypter
|
|
from core.tools.utils.parser import ApiBasedToolSchemaParser
|
|
from extensions.ext_database import db
|
|
from models.tools import ApiToolProvider
|
|
from services.tools.tools_transform_service import ToolTransformService
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class ApiToolManageService:
|
|
@staticmethod
|
|
def parser_api_schema(schema: str) -> Mapping[str, Any]:
|
|
"""
|
|
parse api schema to tool bundle
|
|
"""
|
|
try:
|
|
warnings: dict[str, str] = {}
|
|
try:
|
|
tool_bundles, schema_type = ApiBasedToolSchemaParser.auto_parse_to_tool_bundle(schema, warning=warnings)
|
|
except Exception as e:
|
|
raise ValueError(f"invalid schema: {str(e)}")
|
|
|
|
credentials_schema = [
|
|
ProviderConfig(
|
|
name="auth_type",
|
|
type=ProviderConfig.Type.SELECT,
|
|
required=True,
|
|
default="none",
|
|
options=[
|
|
ProviderConfig.Option(value="none", label=I18nObject(en_US="None", zh_Hans="无")),
|
|
ProviderConfig.Option(value="api_key", label=I18nObject(en_US="Api Key", zh_Hans="Api Key")),
|
|
],
|
|
placeholder=I18nObject(en_US="Select auth type", zh_Hans="选择认证方式"),
|
|
),
|
|
ProviderConfig(
|
|
name="api_key_header",
|
|
type=ProviderConfig.Type.TEXT_INPUT,
|
|
required=False,
|
|
placeholder=I18nObject(en_US="Enter api key header", zh_Hans="输入 api key header,如:X-API-KEY"),
|
|
default="api_key",
|
|
help=I18nObject(en_US="HTTP header name for api key", zh_Hans="HTTP 头部字段名,用于传递 api key"),
|
|
),
|
|
ProviderConfig(
|
|
name="api_key_value",
|
|
type=ProviderConfig.Type.TEXT_INPUT,
|
|
required=False,
|
|
placeholder=I18nObject(en_US="Enter api key", zh_Hans="输入 api key"),
|
|
default="",
|
|
),
|
|
]
|
|
|
|
return cast(
|
|
Mapping,
|
|
jsonable_encoder(
|
|
{
|
|
"schema_type": schema_type,
|
|
"parameters_schema": tool_bundles,
|
|
"credentials_schema": credentials_schema,
|
|
"warning": warnings,
|
|
}
|
|
),
|
|
)
|
|
except Exception as e:
|
|
raise ValueError(f"invalid schema: {str(e)}")
|
|
|
|
@staticmethod
|
|
def convert_schema_to_tool_bundles(schema: str, extra_info: dict | None = None) -> tuple[list[ApiToolBundle], str]:
|
|
"""
|
|
convert schema to tool bundles
|
|
|
|
:return: the list of tool bundles, description
|
|
"""
|
|
try:
|
|
return ApiBasedToolSchemaParser.auto_parse_to_tool_bundle(schema, extra_info=extra_info)
|
|
except Exception as e:
|
|
raise ValueError(f"invalid schema: {str(e)}")
|
|
|
|
@staticmethod
|
|
def create_api_tool_provider(
|
|
user_id: str,
|
|
tenant_id: str,
|
|
provider_name: str,
|
|
icon: dict,
|
|
credentials: dict,
|
|
schema_type: str,
|
|
schema: str,
|
|
privacy_policy: str,
|
|
custom_disclaimer: str,
|
|
labels: list[str],
|
|
):
|
|
"""
|
|
create api tool provider
|
|
"""
|
|
if schema_type not in [member.value for member in ApiProviderSchemaType]:
|
|
raise ValueError(f"invalid schema type {schema}")
|
|
|
|
provider_name = provider_name.strip()
|
|
|
|
# check if the provider exists
|
|
provider = (
|
|
db.session.query(ApiToolProvider)
|
|
.filter(
|
|
ApiToolProvider.tenant_id == tenant_id,
|
|
ApiToolProvider.name == provider_name,
|
|
)
|
|
.first()
|
|
)
|
|
|
|
if provider is not None:
|
|
raise ValueError(f"provider {provider_name} already exists")
|
|
|
|
# parse openapi to tool bundle
|
|
extra_info: dict[str, str] = {}
|
|
# extra info like description will be set here
|
|
tool_bundles, schema_type = ApiToolManageService.convert_schema_to_tool_bundles(schema, extra_info)
|
|
|
|
if len(tool_bundles) > 100:
|
|
raise ValueError("the number of apis should be less than 100")
|
|
|
|
# create db provider
|
|
db_provider = ApiToolProvider(
|
|
tenant_id=tenant_id,
|
|
user_id=user_id,
|
|
name=provider_name,
|
|
icon=json.dumps(icon),
|
|
schema=schema,
|
|
description=extra_info.get("description", ""),
|
|
schema_type_str=schema_type,
|
|
tools_str=json.dumps(jsonable_encoder(tool_bundles)),
|
|
credentials_str={},
|
|
privacy_policy=privacy_policy,
|
|
custom_disclaimer=custom_disclaimer,
|
|
)
|
|
|
|
if "auth_type" not in credentials:
|
|
raise ValueError("auth_type is required")
|
|
|
|
# get auth type, none or api key
|
|
auth_type = ApiProviderAuthType.value_of(credentials["auth_type"])
|
|
|
|
# create provider entity
|
|
provider_controller = ApiToolProviderController.from_db(db_provider, auth_type)
|
|
# load tools into provider entity
|
|
provider_controller.load_bundled_tools(tool_bundles)
|
|
|
|
# encrypt credentials
|
|
tool_configuration = ProviderConfigEncrypter(
|
|
tenant_id=tenant_id,
|
|
config=list(provider_controller.get_credentials_schema()),
|
|
provider_type=provider_controller.provider_type.value,
|
|
provider_identity=provider_controller.entity.identity.name,
|
|
)
|
|
|
|
encrypted_credentials = tool_configuration.encrypt(credentials)
|
|
db_provider.credentials_str = json.dumps(encrypted_credentials)
|
|
|
|
db.session.add(db_provider)
|
|
db.session.commit()
|
|
|
|
# update labels
|
|
ToolLabelManager.update_tool_labels(provider_controller, labels)
|
|
|
|
return {"result": "success"}
|
|
|
|
@staticmethod
|
|
def get_api_tool_provider_remote_schema(user_id: str, tenant_id: str, url: str):
|
|
"""
|
|
get api tool provider remote schema
|
|
"""
|
|
headers = {
|
|
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko)"
|
|
" Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0",
|
|
"Accept": "*/*",
|
|
}
|
|
|
|
try:
|
|
response = get(url, headers=headers, timeout=10)
|
|
if response.status_code != 200:
|
|
raise ValueError(f"Got status code {response.status_code}")
|
|
schema = response.text
|
|
|
|
# try to parse schema, avoid SSRF attack
|
|
ApiToolManageService.parser_api_schema(schema)
|
|
except Exception:
|
|
logger.exception("parse api schema error")
|
|
raise ValueError("invalid schema, please check the url you provided")
|
|
|
|
return {"schema": schema}
|
|
|
|
@staticmethod
|
|
def list_api_tool_provider_tools(user_id: str, tenant_id: str, provider_name: str) -> list[ToolApiEntity]:
|
|
"""
|
|
list api tool provider tools
|
|
"""
|
|
provider: ApiToolProvider | None = (
|
|
db.session.query(ApiToolProvider)
|
|
.filter(
|
|
ApiToolProvider.tenant_id == tenant_id,
|
|
ApiToolProvider.name == provider_name,
|
|
)
|
|
.first()
|
|
)
|
|
|
|
if provider is None:
|
|
raise ValueError(f"you have not added provider {provider_name}")
|
|
|
|
controller = ToolTransformService.api_provider_to_controller(db_provider=provider)
|
|
labels = ToolLabelManager.get_tool_labels(controller)
|
|
|
|
return [
|
|
ToolTransformService.convert_tool_entity_to_api_entity(
|
|
tool_bundle,
|
|
tenant_id=tenant_id,
|
|
labels=labels,
|
|
)
|
|
for tool_bundle in provider.tools
|
|
]
|
|
|
|
@staticmethod
|
|
def update_api_tool_provider(
|
|
user_id: str,
|
|
tenant_id: str,
|
|
provider_name: str,
|
|
original_provider: str,
|
|
icon: dict,
|
|
credentials: dict,
|
|
schema_type: str,
|
|
schema: str,
|
|
privacy_policy: str,
|
|
custom_disclaimer: str,
|
|
labels: list[str],
|
|
):
|
|
"""
|
|
update api tool provider
|
|
"""
|
|
if schema_type not in [member.value for member in ApiProviderSchemaType]:
|
|
raise ValueError(f"invalid schema type {schema}")
|
|
|
|
provider_name = provider_name.strip()
|
|
|
|
# check if the provider exists
|
|
provider = (
|
|
db.session.query(ApiToolProvider)
|
|
.filter(
|
|
ApiToolProvider.tenant_id == tenant_id,
|
|
ApiToolProvider.name == original_provider,
|
|
)
|
|
.first()
|
|
)
|
|
|
|
if provider is None:
|
|
raise ValueError(f"api provider {provider_name} does not exists")
|
|
# parse openapi to tool bundle
|
|
extra_info: dict[str, str] = {}
|
|
# extra info like description will be set here
|
|
tool_bundles, schema_type = ApiToolManageService.convert_schema_to_tool_bundles(schema, extra_info)
|
|
|
|
# update db provider
|
|
provider.name = provider_name
|
|
provider.icon = json.dumps(icon)
|
|
provider.schema = schema
|
|
provider.description = extra_info.get("description", "")
|
|
provider.schema_type_str = ApiProviderSchemaType.OPENAPI.value
|
|
provider.tools_str = json.dumps(jsonable_encoder(tool_bundles))
|
|
provider.privacy_policy = privacy_policy
|
|
provider.custom_disclaimer = custom_disclaimer
|
|
|
|
if "auth_type" not in credentials:
|
|
raise ValueError("auth_type is required")
|
|
|
|
# get auth type, none or api key
|
|
auth_type = ApiProviderAuthType.value_of(credentials["auth_type"])
|
|
|
|
# create provider entity
|
|
provider_controller = ApiToolProviderController.from_db(provider, auth_type)
|
|
# load tools into provider entity
|
|
provider_controller.load_bundled_tools(tool_bundles)
|
|
|
|
# get original credentials if exists
|
|
tool_configuration = ProviderConfigEncrypter(
|
|
tenant_id=tenant_id,
|
|
config=list(provider_controller.get_credentials_schema()),
|
|
provider_type=provider_controller.provider_type.value,
|
|
provider_identity=provider_controller.entity.identity.name,
|
|
)
|
|
|
|
original_credentials = tool_configuration.decrypt(provider.credentials)
|
|
masked_credentials = tool_configuration.mask_tool_credentials(original_credentials)
|
|
# check if the credential has changed, save the original credential
|
|
for name, value in credentials.items():
|
|
if name in masked_credentials and value == masked_credentials[name]:
|
|
credentials[name] = original_credentials[name]
|
|
|
|
credentials = tool_configuration.encrypt(credentials)
|
|
provider.credentials_str = json.dumps(credentials)
|
|
|
|
db.session.add(provider)
|
|
db.session.commit()
|
|
|
|
# delete cache
|
|
tool_configuration.delete_tool_credentials_cache()
|
|
|
|
# update labels
|
|
ToolLabelManager.update_tool_labels(provider_controller, labels)
|
|
|
|
return {"result": "success"}
|
|
|
|
@staticmethod
|
|
def delete_api_tool_provider(user_id: str, tenant_id: str, provider_name: str):
|
|
"""
|
|
delete tool provider
|
|
"""
|
|
provider = (
|
|
db.session.query(ApiToolProvider)
|
|
.filter(
|
|
ApiToolProvider.tenant_id == tenant_id,
|
|
ApiToolProvider.name == provider_name,
|
|
)
|
|
.first()
|
|
)
|
|
|
|
if provider is None:
|
|
raise ValueError(f"you have not added provider {provider_name}")
|
|
|
|
db.session.delete(provider)
|
|
db.session.commit()
|
|
|
|
return {"result": "success"}
|
|
|
|
@staticmethod
|
|
def get_api_tool_provider(user_id: str, tenant_id: str, provider: str):
|
|
"""
|
|
get api tool provider
|
|
"""
|
|
return ToolManager.user_get_api_provider(provider=provider, tenant_id=tenant_id)
|
|
|
|
@staticmethod
|
|
def test_api_tool_preview(
|
|
tenant_id: str,
|
|
provider_name: str,
|
|
tool_name: str,
|
|
credentials: dict,
|
|
parameters: dict,
|
|
schema_type: str,
|
|
schema: str,
|
|
):
|
|
"""
|
|
test api tool before adding api tool provider
|
|
"""
|
|
if schema_type not in [member.value for member in ApiProviderSchemaType]:
|
|
raise ValueError(f"invalid schema type {schema_type}")
|
|
|
|
try:
|
|
tool_bundles, _ = ApiBasedToolSchemaParser.auto_parse_to_tool_bundle(schema)
|
|
except Exception:
|
|
raise ValueError("invalid schema")
|
|
|
|
# get tool bundle
|
|
tool_bundle = next(filter(lambda tb: tb.operation_id == tool_name, tool_bundles), None)
|
|
if tool_bundle is None:
|
|
raise ValueError(f"invalid tool name {tool_name}")
|
|
|
|
db_provider = (
|
|
db.session.query(ApiToolProvider)
|
|
.filter(
|
|
ApiToolProvider.tenant_id == tenant_id,
|
|
ApiToolProvider.name == provider_name,
|
|
)
|
|
.first()
|
|
)
|
|
|
|
if not db_provider:
|
|
# create a fake db provider
|
|
db_provider = ApiToolProvider(
|
|
tenant_id="",
|
|
user_id="",
|
|
name="",
|
|
icon="",
|
|
schema=schema,
|
|
description="",
|
|
schema_type_str=ApiProviderSchemaType.OPENAPI.value,
|
|
tools_str=json.dumps(jsonable_encoder(tool_bundles)),
|
|
credentials_str=json.dumps(credentials),
|
|
)
|
|
|
|
if "auth_type" not in credentials:
|
|
raise ValueError("auth_type is required")
|
|
|
|
# get auth type, none or api key
|
|
auth_type = ApiProviderAuthType.value_of(credentials["auth_type"])
|
|
|
|
# create provider entity
|
|
provider_controller = ApiToolProviderController.from_db(db_provider, auth_type)
|
|
# load tools into provider entity
|
|
provider_controller.load_bundled_tools(tool_bundles)
|
|
|
|
# decrypt credentials
|
|
if db_provider.id:
|
|
tool_configuration = ProviderConfigEncrypter(
|
|
tenant_id=tenant_id,
|
|
config=list(provider_controller.get_credentials_schema()),
|
|
provider_type=provider_controller.provider_type.value,
|
|
provider_identity=provider_controller.entity.identity.name,
|
|
)
|
|
decrypted_credentials = tool_configuration.decrypt(credentials)
|
|
# check if the credential has changed, save the original credential
|
|
masked_credentials = tool_configuration.mask_tool_credentials(decrypted_credentials)
|
|
for name, value in credentials.items():
|
|
if name in masked_credentials and value == masked_credentials[name]:
|
|
credentials[name] = decrypted_credentials[name]
|
|
|
|
try:
|
|
provider_controller.validate_credentials_format(credentials)
|
|
# get tool
|
|
tool = provider_controller.get_tool(tool_name)
|
|
tool = tool.fork_tool_runtime(
|
|
runtime=ToolRuntime(
|
|
credentials=credentials,
|
|
tenant_id=tenant_id,
|
|
)
|
|
)
|
|
result = tool.validate_credentials(credentials, parameters)
|
|
except Exception as e:
|
|
return {"error": str(e)}
|
|
|
|
return {"result": result or "empty response"}
|
|
|
|
@staticmethod
|
|
def list_api_tools(user_id: str, tenant_id: str) -> list[ToolProviderApiEntity]:
|
|
"""
|
|
list api tools
|
|
"""
|
|
# get all api providers
|
|
db_providers: list[ApiToolProvider] = (
|
|
db.session.query(ApiToolProvider).filter(ApiToolProvider.tenant_id == tenant_id).all() or []
|
|
)
|
|
|
|
result: list[ToolProviderApiEntity] = []
|
|
|
|
for provider in db_providers:
|
|
# convert provider controller to user provider
|
|
provider_controller = ToolTransformService.api_provider_to_controller(db_provider=provider)
|
|
labels = ToolLabelManager.get_tool_labels(provider_controller)
|
|
user_provider = ToolTransformService.api_provider_to_user_provider(
|
|
provider_controller, db_provider=provider, decrypt_credentials=True
|
|
)
|
|
user_provider.labels = labels
|
|
|
|
# add icon
|
|
ToolTransformService.repack_provider(tenant_id=tenant_id, provider=user_provider)
|
|
|
|
tools = provider_controller.get_tools(tenant_id=tenant_id)
|
|
|
|
for tool in tools or []:
|
|
user_provider.tools.append(
|
|
ToolTransformService.convert_tool_entity_to_api_entity(
|
|
tenant_id=tenant_id, tool=tool, credentials=user_provider.original_credentials, labels=labels
|
|
)
|
|
)
|
|
|
|
result.append(user_provider)
|
|
|
|
return result
|