Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555
  1. import json
  2. from collections.abc import Mapping
  3. from datetime import datetime
  4. from typing import TYPE_CHECKING, Any, cast
  5. from urllib.parse import urlparse
  6. import sqlalchemy as sa
  7. from deprecated import deprecated
  8. from sqlalchemy import ForeignKey, String, func
  9. from sqlalchemy.orm import Mapped, mapped_column
  10. from core.helper import encrypter
  11. from core.tools.entities.common_entities import I18nObject
  12. from core.tools.entities.tool_bundle import ApiToolBundle
  13. from core.tools.entities.tool_entities import ApiProviderSchemaType, WorkflowToolParameterConfiguration
  14. from models.base import Base, TypeBase
  15. from .engine import db
  16. from .model import Account, App, Tenant
  17. from .types import StringUUID
  18. if TYPE_CHECKING:
  19. from core.mcp.types import Tool as MCPTool
  20. from core.tools.entities.common_entities import I18nObject
  21. from core.tools.entities.tool_bundle import ApiToolBundle
  22. from core.tools.entities.tool_entities import ApiProviderSchemaType, WorkflowToolParameterConfiguration
  23. # system level tool oauth client params (client_id, client_secret, etc.)
  24. class ToolOAuthSystemClient(TypeBase):
  25. __tablename__ = "tool_oauth_system_clients"
  26. __table_args__ = (
  27. sa.PrimaryKeyConstraint("id", name="tool_oauth_system_client_pkey"),
  28. sa.UniqueConstraint("plugin_id", "provider", name="tool_oauth_system_client_plugin_id_provider_idx"),
  29. )
  30. id: Mapped[str] = mapped_column(StringUUID, server_default=sa.text("uuid_generate_v4()"), init=False)
  31. plugin_id: Mapped[str] = mapped_column(String(512), nullable=False)
  32. provider: Mapped[str] = mapped_column(String(255), nullable=False)
  33. # oauth params of the tool provider
  34. encrypted_oauth_params: Mapped[str] = mapped_column(sa.Text, nullable=False)
  35. # tenant level tool oauth client params (client_id, client_secret, etc.)
  36. class ToolOAuthTenantClient(Base):
  37. __tablename__ = "tool_oauth_tenant_clients"
  38. __table_args__ = (
  39. sa.PrimaryKeyConstraint("id", name="tool_oauth_tenant_client_pkey"),
  40. sa.UniqueConstraint("tenant_id", "plugin_id", "provider", name="unique_tool_oauth_tenant_client"),
  41. )
  42. id: Mapped[str] = mapped_column(StringUUID, server_default=sa.text("uuid_generate_v4()"))
  43. # tenant id
  44. tenant_id: Mapped[str] = mapped_column(StringUUID, nullable=False)
  45. plugin_id: Mapped[str] = mapped_column(String(512), nullable=False)
  46. provider: Mapped[str] = mapped_column(String(255), nullable=False)
  47. enabled: Mapped[bool] = mapped_column(sa.Boolean, nullable=False, server_default=sa.text("true"))
  48. # oauth params of the tool provider
  49. encrypted_oauth_params: Mapped[str] = mapped_column(sa.Text, nullable=False)
  50. @property
  51. def oauth_params(self) -> dict[str, Any]:
  52. return cast(dict[str, Any], json.loads(self.encrypted_oauth_params or "{}"))
  53. class BuiltinToolProvider(Base):
  54. """
  55. This table stores the tool provider information for built-in tools for each tenant.
  56. """
  57. __tablename__ = "tool_builtin_providers"
  58. __table_args__ = (
  59. sa.PrimaryKeyConstraint("id", name="tool_builtin_provider_pkey"),
  60. sa.UniqueConstraint("tenant_id", "provider", "name", name="unique_builtin_tool_provider"),
  61. )
  62. # id of the tool provider
  63. id: Mapped[str] = mapped_column(StringUUID, server_default=sa.text("uuid_generate_v4()"))
  64. name: Mapped[str] = mapped_column(
  65. String(256), nullable=False, server_default=sa.text("'API KEY 1'::character varying")
  66. )
  67. # id of the tenant
  68. tenant_id: Mapped[str] = mapped_column(StringUUID, nullable=True)
  69. # who created this tool provider
  70. user_id: Mapped[str] = mapped_column(StringUUID, nullable=False)
  71. # name of the tool provider
  72. provider: Mapped[str] = mapped_column(String(256), nullable=False)
  73. # credential of the tool provider
  74. encrypted_credentials: Mapped[str] = mapped_column(sa.Text, nullable=True)
  75. created_at: Mapped[datetime] = mapped_column(
  76. sa.DateTime, nullable=False, server_default=sa.text("CURRENT_TIMESTAMP(0)")
  77. )
  78. updated_at: Mapped[datetime] = mapped_column(
  79. sa.DateTime, nullable=False, server_default=sa.text("CURRENT_TIMESTAMP(0)")
  80. )
  81. is_default: Mapped[bool] = mapped_column(sa.Boolean, nullable=False, server_default=sa.text("false"))
  82. # credential type, e.g., "api-key", "oauth2"
  83. credential_type: Mapped[str] = mapped_column(
  84. String(32), nullable=False, server_default=sa.text("'api-key'::character varying")
  85. )
  86. expires_at: Mapped[int] = mapped_column(sa.BigInteger, nullable=False, server_default=sa.text("-1"))
  87. @property
  88. def credentials(self) -> dict[str, Any]:
  89. return cast(dict[str, Any], json.loads(self.encrypted_credentials))
  90. class ApiToolProvider(Base):
  91. """
  92. The table stores the api providers.
  93. """
  94. __tablename__ = "tool_api_providers"
  95. __table_args__ = (
  96. sa.PrimaryKeyConstraint("id", name="tool_api_provider_pkey"),
  97. sa.UniqueConstraint("name", "tenant_id", name="unique_api_tool_provider"),
  98. )
  99. id = mapped_column(StringUUID, server_default=sa.text("uuid_generate_v4()"))
  100. # name of the api provider
  101. name = mapped_column(String(255), nullable=False, server_default=sa.text("'API KEY 1'::character varying"))
  102. # icon
  103. icon: Mapped[str] = mapped_column(String(255), nullable=False)
  104. # original schema
  105. schema = mapped_column(sa.Text, nullable=False)
  106. schema_type_str: Mapped[str] = mapped_column(String(40), nullable=False)
  107. # who created this tool
  108. user_id = mapped_column(StringUUID, nullable=False)
  109. # tenant id
  110. tenant_id = mapped_column(StringUUID, nullable=False)
  111. # description of the provider
  112. description = mapped_column(sa.Text, nullable=False)
  113. # json format tools
  114. tools_str = mapped_column(sa.Text, nullable=False)
  115. # json format credentials
  116. credentials_str = mapped_column(sa.Text, nullable=False)
  117. # privacy policy
  118. privacy_policy = mapped_column(String(255), nullable=True)
  119. # custom_disclaimer
  120. custom_disclaimer: Mapped[str] = mapped_column(sa.TEXT, default="")
  121. created_at: Mapped[datetime] = mapped_column(sa.DateTime, nullable=False, server_default=func.current_timestamp())
  122. updated_at: Mapped[datetime] = mapped_column(sa.DateTime, nullable=False, server_default=func.current_timestamp())
  123. @property
  124. def schema_type(self) -> "ApiProviderSchemaType":
  125. from core.tools.entities.tool_entities import ApiProviderSchemaType
  126. return ApiProviderSchemaType.value_of(self.schema_type_str)
  127. @property
  128. def tools(self) -> list["ApiToolBundle"]:
  129. from core.tools.entities.tool_bundle import ApiToolBundle
  130. return [ApiToolBundle(**tool) for tool in json.loads(self.tools_str)]
  131. @property
  132. def credentials(self) -> dict[str, Any]:
  133. return dict[str, Any](json.loads(self.credentials_str))
  134. @property
  135. def user(self) -> Account | None:
  136. if not self.user_id:
  137. return None
  138. return db.session.query(Account).where(Account.id == self.user_id).first()
  139. @property
  140. def tenant(self) -> Tenant | None:
  141. return db.session.query(Tenant).where(Tenant.id == self.tenant_id).first()
  142. class ToolLabelBinding(TypeBase):
  143. """
  144. The table stores the labels for tools.
  145. """
  146. __tablename__ = "tool_label_bindings"
  147. __table_args__ = (
  148. sa.PrimaryKeyConstraint("id", name="tool_label_bind_pkey"),
  149. sa.UniqueConstraint("tool_id", "label_name", name="unique_tool_label_bind"),
  150. )
  151. id: Mapped[str] = mapped_column(StringUUID, server_default=sa.text("uuid_generate_v4()"), init=False)
  152. # tool id
  153. tool_id: Mapped[str] = mapped_column(String(64), nullable=False)
  154. # tool type
  155. tool_type: Mapped[str] = mapped_column(String(40), nullable=False)
  156. # label name
  157. label_name: Mapped[str] = mapped_column(String(40), nullable=False)
  158. class WorkflowToolProvider(Base):
  159. """
  160. The table stores the workflow providers.
  161. """
  162. __tablename__ = "tool_workflow_providers"
  163. __table_args__ = (
  164. sa.PrimaryKeyConstraint("id", name="tool_workflow_provider_pkey"),
  165. sa.UniqueConstraint("name", "tenant_id", name="unique_workflow_tool_provider"),
  166. sa.UniqueConstraint("tenant_id", "app_id", name="unique_workflow_tool_provider_app_id"),
  167. )
  168. id: Mapped[str] = mapped_column(StringUUID, server_default=sa.text("uuid_generate_v4()"))
  169. # name of the workflow provider
  170. name: Mapped[str] = mapped_column(String(255), nullable=False)
  171. # label of the workflow provider
  172. label: Mapped[str] = mapped_column(String(255), nullable=False, server_default="")
  173. # icon
  174. icon: Mapped[str] = mapped_column(String(255), nullable=False)
  175. # app id of the workflow provider
  176. app_id: Mapped[str] = mapped_column(StringUUID, nullable=False)
  177. # version of the workflow provider
  178. version: Mapped[str] = mapped_column(String(255), nullable=False, server_default="")
  179. # who created this tool
  180. user_id: Mapped[str] = mapped_column(StringUUID, nullable=False)
  181. # tenant id
  182. tenant_id: Mapped[str] = mapped_column(StringUUID, nullable=False)
  183. # description of the provider
  184. description: Mapped[str] = mapped_column(sa.Text, nullable=False)
  185. # parameter configuration
  186. parameter_configuration: Mapped[str] = mapped_column(sa.Text, nullable=False, server_default="[]")
  187. # privacy policy
  188. privacy_policy: Mapped[str] = mapped_column(String(255), nullable=True, server_default="")
  189. created_at: Mapped[datetime] = mapped_column(
  190. sa.DateTime, nullable=False, server_default=sa.text("CURRENT_TIMESTAMP(0)")
  191. )
  192. updated_at: Mapped[datetime] = mapped_column(
  193. sa.DateTime, nullable=False, server_default=sa.text("CURRENT_TIMESTAMP(0)")
  194. )
  195. @property
  196. def user(self) -> Account | None:
  197. return db.session.query(Account).where(Account.id == self.user_id).first()
  198. @property
  199. def tenant(self) -> Tenant | None:
  200. return db.session.query(Tenant).where(Tenant.id == self.tenant_id).first()
  201. @property
  202. def parameter_configurations(self) -> list["WorkflowToolParameterConfiguration"]:
  203. from core.tools.entities.tool_entities import WorkflowToolParameterConfiguration
  204. return [WorkflowToolParameterConfiguration(**config) for config in json.loads(self.parameter_configuration)]
  205. @property
  206. def app(self) -> App | None:
  207. return db.session.query(App).where(App.id == self.app_id).first()
  208. class MCPToolProvider(Base):
  209. """
  210. The table stores the mcp providers.
  211. """
  212. __tablename__ = "tool_mcp_providers"
  213. __table_args__ = (
  214. sa.PrimaryKeyConstraint("id", name="tool_mcp_provider_pkey"),
  215. sa.UniqueConstraint("tenant_id", "server_url_hash", name="unique_mcp_provider_server_url"),
  216. sa.UniqueConstraint("tenant_id", "name", name="unique_mcp_provider_name"),
  217. sa.UniqueConstraint("tenant_id", "server_identifier", name="unique_mcp_provider_server_identifier"),
  218. )
  219. id: Mapped[str] = mapped_column(StringUUID, server_default=sa.text("uuid_generate_v4()"))
  220. # name of the mcp provider
  221. name: Mapped[str] = mapped_column(String(40), nullable=False)
  222. # server identifier of the mcp provider
  223. server_identifier: Mapped[str] = mapped_column(String(64), nullable=False)
  224. # encrypted url of the mcp provider
  225. server_url: Mapped[str] = mapped_column(sa.Text, nullable=False)
  226. # hash of server_url for uniqueness check
  227. server_url_hash: Mapped[str] = mapped_column(String(64), nullable=False)
  228. # icon of the mcp provider
  229. icon: Mapped[str] = mapped_column(String(255), nullable=True)
  230. # tenant id
  231. tenant_id: Mapped[str] = mapped_column(StringUUID, nullable=False)
  232. # who created this tool
  233. user_id: Mapped[str] = mapped_column(StringUUID, nullable=False)
  234. # encrypted credentials
  235. encrypted_credentials: Mapped[str] = mapped_column(sa.Text, nullable=True)
  236. # authed
  237. authed: Mapped[bool] = mapped_column(sa.Boolean, nullable=False, default=False)
  238. # tools
  239. tools: Mapped[str] = mapped_column(sa.Text, nullable=False, default="[]")
  240. created_at: Mapped[datetime] = mapped_column(
  241. sa.DateTime, nullable=False, server_default=sa.text("CURRENT_TIMESTAMP(0)")
  242. )
  243. updated_at: Mapped[datetime] = mapped_column(
  244. sa.DateTime, nullable=False, server_default=sa.text("CURRENT_TIMESTAMP(0)")
  245. )
  246. timeout: Mapped[float] = mapped_column(sa.Float, nullable=False, server_default=sa.text("30"))
  247. sse_read_timeout: Mapped[float] = mapped_column(sa.Float, nullable=False, server_default=sa.text("300"))
  248. # encrypted headers for MCP server requests
  249. encrypted_headers: Mapped[str | None] = mapped_column(sa.Text, nullable=True)
  250. def load_user(self) -> Account | None:
  251. return db.session.query(Account).where(Account.id == self.user_id).first()
  252. @property
  253. def tenant(self) -> Tenant | None:
  254. return db.session.query(Tenant).where(Tenant.id == self.tenant_id).first()
  255. @property
  256. def credentials(self) -> dict[str, Any]:
  257. try:
  258. return cast(dict[str, Any], json.loads(self.encrypted_credentials)) or {}
  259. except Exception:
  260. return {}
  261. @property
  262. def mcp_tools(self) -> list["MCPTool"]:
  263. from core.mcp.types import Tool as MCPTool
  264. return [MCPTool(**tool) for tool in json.loads(self.tools)]
  265. @property
  266. def provider_icon(self) -> Mapping[str, str] | str:
  267. from core.file import helpers as file_helpers
  268. try:
  269. return json.loads(self.icon)
  270. except json.JSONDecodeError:
  271. return file_helpers.get_signed_file_url(self.icon)
  272. @property
  273. def decrypted_server_url(self) -> str:
  274. return encrypter.decrypt_token(self.tenant_id, self.server_url)
  275. @property
  276. def decrypted_headers(self) -> dict[str, Any]:
  277. """Get decrypted headers for MCP server requests."""
  278. from core.entities.provider_entities import BasicProviderConfig
  279. from core.helper.provider_cache import NoOpProviderCredentialCache
  280. from core.tools.utils.encryption import create_provider_encrypter
  281. try:
  282. if not self.encrypted_headers:
  283. return {}
  284. headers_data = json.loads(self.encrypted_headers)
  285. # Create dynamic config for all headers as SECRET_INPUT
  286. config = [BasicProviderConfig(type=BasicProviderConfig.Type.SECRET_INPUT, name=key) for key in headers_data]
  287. encrypter_instance, _ = create_provider_encrypter(
  288. tenant_id=self.tenant_id,
  289. config=config,
  290. cache=NoOpProviderCredentialCache(),
  291. )
  292. result = encrypter_instance.decrypt(headers_data)
  293. return result
  294. except Exception:
  295. return {}
  296. @property
  297. def masked_headers(self) -> dict[str, Any]:
  298. """Get masked headers for frontend display."""
  299. from core.entities.provider_entities import BasicProviderConfig
  300. from core.helper.provider_cache import NoOpProviderCredentialCache
  301. from core.tools.utils.encryption import create_provider_encrypter
  302. try:
  303. if not self.encrypted_headers:
  304. return {}
  305. headers_data = json.loads(self.encrypted_headers)
  306. # Create dynamic config for all headers as SECRET_INPUT
  307. config = [BasicProviderConfig(type=BasicProviderConfig.Type.SECRET_INPUT, name=key) for key in headers_data]
  308. encrypter_instance, _ = create_provider_encrypter(
  309. tenant_id=self.tenant_id,
  310. config=config,
  311. cache=NoOpProviderCredentialCache(),
  312. )
  313. # First decrypt, then mask
  314. decrypted_headers = encrypter_instance.decrypt(headers_data)
  315. result = encrypter_instance.mask_tool_credentials(decrypted_headers)
  316. return result
  317. except Exception:
  318. return {}
  319. @property
  320. def masked_server_url(self) -> str:
  321. def mask_url(url: str, mask_char: str = "*") -> str:
  322. """
  323. mask the url to a simple string
  324. """
  325. parsed = urlparse(url)
  326. base_url = f"{parsed.scheme}://{parsed.netloc}"
  327. if parsed.path and parsed.path != "/":
  328. return f"{base_url}/{mask_char * 6}"
  329. else:
  330. return base_url
  331. return mask_url(self.decrypted_server_url)
  332. @property
  333. def decrypted_credentials(self) -> dict[str, Any]:
  334. from core.helper.provider_cache import NoOpProviderCredentialCache
  335. from core.tools.mcp_tool.provider import MCPToolProviderController
  336. from core.tools.utils.encryption import create_provider_encrypter
  337. provider_controller = MCPToolProviderController.from_db(self)
  338. encrypter, _ = create_provider_encrypter(
  339. tenant_id=self.tenant_id,
  340. config=[x.to_basic_provider_config() for x in provider_controller.get_credentials_schema()],
  341. cache=NoOpProviderCredentialCache(),
  342. )
  343. return encrypter.decrypt(self.credentials)
  344. class ToolModelInvoke(Base):
  345. """
  346. store the invoke logs from tool invoke
  347. """
  348. __tablename__ = "tool_model_invokes"
  349. __table_args__ = (sa.PrimaryKeyConstraint("id", name="tool_model_invoke_pkey"),)
  350. id = mapped_column(StringUUID, server_default=sa.text("uuid_generate_v4()"))
  351. # who invoke this tool
  352. user_id = mapped_column(StringUUID, nullable=False)
  353. # tenant id
  354. tenant_id = mapped_column(StringUUID, nullable=False)
  355. # provider
  356. provider: Mapped[str] = mapped_column(String(255), nullable=False)
  357. # type
  358. tool_type = mapped_column(String(40), nullable=False)
  359. # tool name
  360. tool_name = mapped_column(String(128), nullable=False)
  361. # invoke parameters
  362. model_parameters = mapped_column(sa.Text, nullable=False)
  363. # prompt messages
  364. prompt_messages = mapped_column(sa.Text, nullable=False)
  365. # invoke response
  366. model_response = mapped_column(sa.Text, nullable=False)
  367. prompt_tokens: Mapped[int] = mapped_column(sa.Integer, nullable=False, server_default=sa.text("0"))
  368. answer_tokens: Mapped[int] = mapped_column(sa.Integer, nullable=False, server_default=sa.text("0"))
  369. answer_unit_price = mapped_column(sa.Numeric(10, 4), nullable=False)
  370. answer_price_unit = mapped_column(sa.Numeric(10, 7), nullable=False, server_default=sa.text("0.001"))
  371. provider_response_latency = mapped_column(sa.Float, nullable=False, server_default=sa.text("0"))
  372. total_price = mapped_column(sa.Numeric(10, 7))
  373. currency: Mapped[str] = mapped_column(String(255), nullable=False)
  374. created_at = mapped_column(sa.DateTime, nullable=False, server_default=func.current_timestamp())
  375. updated_at = mapped_column(sa.DateTime, nullable=False, server_default=func.current_timestamp())
  376. @deprecated
  377. class ToolConversationVariables(Base):
  378. """
  379. store the conversation variables from tool invoke
  380. """
  381. __tablename__ = "tool_conversation_variables"
  382. __table_args__ = (
  383. sa.PrimaryKeyConstraint("id", name="tool_conversation_variables_pkey"),
  384. # add index for user_id and conversation_id
  385. sa.Index("user_id_idx", "user_id"),
  386. sa.Index("conversation_id_idx", "conversation_id"),
  387. )
  388. id = mapped_column(StringUUID, server_default=sa.text("uuid_generate_v4()"))
  389. # conversation user id
  390. user_id = mapped_column(StringUUID, nullable=False)
  391. # tenant id
  392. tenant_id = mapped_column(StringUUID, nullable=False)
  393. # conversation id
  394. conversation_id = mapped_column(StringUUID, nullable=False)
  395. # variables pool
  396. variables_str = mapped_column(sa.Text, nullable=False)
  397. created_at = mapped_column(sa.DateTime, nullable=False, server_default=func.current_timestamp())
  398. updated_at = mapped_column(sa.DateTime, nullable=False, server_default=func.current_timestamp())
  399. @property
  400. def variables(self):
  401. return json.loads(self.variables_str)
  402. class ToolFile(TypeBase):
  403. """This table stores file metadata generated in workflows,
  404. not only files created by agent.
  405. """
  406. __tablename__ = "tool_files"
  407. __table_args__ = (
  408. sa.PrimaryKeyConstraint("id", name="tool_file_pkey"),
  409. sa.Index("tool_file_conversation_id_idx", "conversation_id"),
  410. )
  411. id: Mapped[str] = mapped_column(StringUUID, server_default=sa.text("uuid_generate_v4()"), init=False)
  412. # conversation user id
  413. user_id: Mapped[str] = mapped_column(StringUUID)
  414. # tenant id
  415. tenant_id: Mapped[str] = mapped_column(StringUUID)
  416. # conversation id
  417. conversation_id: Mapped[str | None] = mapped_column(StringUUID, nullable=True)
  418. # file key
  419. file_key: Mapped[str] = mapped_column(String(255), nullable=False)
  420. # mime type
  421. mimetype: Mapped[str] = mapped_column(String(255), nullable=False)
  422. # original url
  423. original_url: Mapped[str | None] = mapped_column(String(2048), nullable=True, default=None)
  424. # name
  425. name: Mapped[str] = mapped_column(default="")
  426. # size
  427. size: Mapped[int] = mapped_column(default=-1)
  428. @deprecated
  429. class DeprecatedPublishedAppTool(Base):
  430. """
  431. The table stores the apps published as a tool for each person.
  432. """
  433. __tablename__ = "tool_published_apps"
  434. __table_args__ = (
  435. sa.PrimaryKeyConstraint("id", name="published_app_tool_pkey"),
  436. sa.UniqueConstraint("app_id", "user_id", name="unique_published_app_tool"),
  437. )
  438. id = mapped_column(StringUUID, server_default=sa.text("uuid_generate_v4()"))
  439. # id of the app
  440. app_id = mapped_column(StringUUID, ForeignKey("apps.id"), nullable=False)
  441. user_id: Mapped[str] = mapped_column(StringUUID, nullable=False)
  442. # who published this tool
  443. description = mapped_column(sa.Text, nullable=False)
  444. # llm_description of the tool, for LLM
  445. llm_description = mapped_column(sa.Text, nullable=False)
  446. # query description, query will be seem as a parameter of the tool,
  447. # to describe this parameter to llm, we need this field
  448. query_description = mapped_column(sa.Text, nullable=False)
  449. # query name, the name of the query parameter
  450. query_name = mapped_column(String(40), nullable=False)
  451. # name of the tool provider
  452. tool_name = mapped_column(String(40), nullable=False)
  453. # author
  454. author = mapped_column(String(40), nullable=False)
  455. created_at = mapped_column(sa.DateTime, nullable=False, server_default=sa.text("CURRENT_TIMESTAMP(0)"))
  456. updated_at = mapped_column(sa.DateTime, nullable=False, server_default=sa.text("CURRENT_TIMESTAMP(0)"))
  457. @property
  458. def description_i18n(self) -> "I18nObject":
  459. from core.tools.entities.common_entities import I18nObject
  460. return I18nObject(**json.loads(self.description))