mirror of
https://github.com/langgenius/dify.git
synced 2026-01-08 07:14:14 +00:00
Introduce Plugins (#13836)
Signed-off-by: yihong0618 <zouzou0208@gmail.com> Signed-off-by: -LAN- <laipz8200@outlook.com> Signed-off-by: xhe <xw897002528@gmail.com> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: takatost <takatost@gmail.com> Co-authored-by: kurokobo <kuro664@gmail.com> Co-authored-by: Novice Lee <novicelee@NoviPro.local> Co-authored-by: zxhlyh <jasonapring2015@outlook.com> Co-authored-by: AkaraChen <akarachen@outlook.com> Co-authored-by: Yi <yxiaoisme@gmail.com> Co-authored-by: Joel <iamjoel007@gmail.com> Co-authored-by: JzoNg <jzongcode@gmail.com> Co-authored-by: twwu <twwu@dify.ai> Co-authored-by: Hiroshi Fujita <fujita-h@users.noreply.github.com> Co-authored-by: AkaraChen <85140972+AkaraChen@users.noreply.github.com> Co-authored-by: NFish <douxc512@gmail.com> Co-authored-by: Wu Tianwei <30284043+WTW0313@users.noreply.github.com> Co-authored-by: 非法操作 <hjlarry@163.com> Co-authored-by: Novice <857526207@qq.com> Co-authored-by: Hiroki Nagai <82458324+nagaihiroki-git@users.noreply.github.com> Co-authored-by: Gen Sato <52241300+halogen22@users.noreply.github.com> Co-authored-by: eux <euxuuu@gmail.com> Co-authored-by: huangzhuo1949 <167434202+huangzhuo1949@users.noreply.github.com> Co-authored-by: huangzhuo <huangzhuo1@xiaomi.com> Co-authored-by: lotsik <lotsik@mail.ru> Co-authored-by: crazywoola <100913391+crazywoola@users.noreply.github.com> Co-authored-by: nite-knite <nkCoding@gmail.com> Co-authored-by: Jyong <76649700+JohnJyong@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: gakkiyomi <gakkiyomi@aliyun.com> Co-authored-by: CN-P5 <heibai2006@gmail.com> Co-authored-by: CN-P5 <heibai2006@qq.com> Co-authored-by: Chuehnone <1897025+chuehnone@users.noreply.github.com> Co-authored-by: yihong <zouzou0208@gmail.com> Co-authored-by: Kevin9703 <51311316+Kevin9703@users.noreply.github.com> Co-authored-by: -LAN- <laipz8200@outlook.com> Co-authored-by: Boris Feld <lothiraldan@gmail.com> Co-authored-by: mbo <himabo@gmail.com> Co-authored-by: mabo <mabo@aeyes.ai> Co-authored-by: Warren Chen <warren.chen830@gmail.com> Co-authored-by: JzoNgKVO <27049666+JzoNgKVO@users.noreply.github.com> Co-authored-by: jiandanfeng <chenjh3@wangsu.com> Co-authored-by: zhu-an <70234959+xhdd123321@users.noreply.github.com> Co-authored-by: zhaoqingyu.1075 <zhaoqingyu.1075@bytedance.com> Co-authored-by: 海狸大師 <86974027+yenslife@users.noreply.github.com> Co-authored-by: Xu Song <xusong.vip@gmail.com> Co-authored-by: rayshaw001 <396301947@163.com> Co-authored-by: Ding Jiatong <dingjiatong@gmail.com> Co-authored-by: Bowen Liang <liangbowen@gf.com.cn> Co-authored-by: JasonVV <jasonwangiii@outlook.com> Co-authored-by: le0zh <newlight@qq.com> Co-authored-by: zhuxinliang <zhuxinliang@didiglobal.com> Co-authored-by: k-zaku <zaku99@outlook.jp> Co-authored-by: luckylhb90 <luckylhb90@gmail.com> Co-authored-by: hobo.l <hobo.l@binance.com> Co-authored-by: jiangbo721 <365065261@qq.com> Co-authored-by: 刘江波 <jiangbo721@163.com> Co-authored-by: Shun Miyazawa <34241526+miya@users.noreply.github.com> Co-authored-by: EricPan <30651140+Egfly@users.noreply.github.com> Co-authored-by: crazywoola <427733928@qq.com> Co-authored-by: sino <sino2322@gmail.com> Co-authored-by: Jhvcc <37662342+Jhvcc@users.noreply.github.com> Co-authored-by: lowell <lowell.hu@zkteco.in> Co-authored-by: Boris Polonsky <BorisPolonsky@users.noreply.github.com> Co-authored-by: Ademílson Tonato <ademilsonft@outlook.com> Co-authored-by: Ademílson Tonato <ademilson.tonato@refurbed.com> Co-authored-by: IWAI, Masaharu <iwaim.sub@gmail.com> Co-authored-by: Yueh-Po Peng (Yabi) <94939112+y10ab1@users.noreply.github.com> Co-authored-by: Jason <ggbbddjm@gmail.com> Co-authored-by: Xin Zhang <sjhpzx@gmail.com> Co-authored-by: yjc980121 <3898524+yjc980121@users.noreply.github.com> Co-authored-by: heyszt <36215648+hieheihei@users.noreply.github.com> Co-authored-by: Abdullah AlOsaimi <osaimiacc@gmail.com> Co-authored-by: Abdullah AlOsaimi <189027247+osaimi@users.noreply.github.com> Co-authored-by: Yingchun Lai <laiyingchun@apache.org> Co-authored-by: Hash Brown <hi@xzd.me> Co-authored-by: zuodongxu <192560071+zuodongxu@users.noreply.github.com> Co-authored-by: Masashi Tomooka <tmokmss@users.noreply.github.com> Co-authored-by: aplio <ryo.091219@gmail.com> Co-authored-by: Obada Khalili <54270856+obadakhalili@users.noreply.github.com> Co-authored-by: Nam Vu <zuzoovn@gmail.com> Co-authored-by: Kei YAMAZAKI <1715090+kei-yamazaki@users.noreply.github.com> Co-authored-by: TechnoHouse <13776377+deephbz@users.noreply.github.com> Co-authored-by: Riddhimaan-Senapati <114703025+Riddhimaan-Senapati@users.noreply.github.com> Co-authored-by: MaFee921 <31881301+2284730142@users.noreply.github.com> Co-authored-by: te-chan <t-nakanome@sakura-is.co.jp> Co-authored-by: HQidea <HQidea@users.noreply.github.com> Co-authored-by: Joshbly <36315710+Joshbly@users.noreply.github.com> Co-authored-by: xhe <xw897002528@gmail.com> Co-authored-by: weiwenyan-dev <154779315+weiwenyan-dev@users.noreply.github.com> Co-authored-by: ex_wenyan.wei <ex_wenyan.wei@tcl.com> Co-authored-by: engchina <12236799+engchina@users.noreply.github.com> Co-authored-by: engchina <atjapan2015@gmail.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: 呆萌闷油瓶 <253605712@qq.com> Co-authored-by: Kemal <kemalmeler@outlook.com> Co-authored-by: Lazy_Frog <4590648+lazyFrogLOL@users.noreply.github.com> Co-authored-by: Yi Xiao <54782454+YIXIAO0@users.noreply.github.com> Co-authored-by: Steven sun <98230804+Tuyohai@users.noreply.github.com> Co-authored-by: steven <sunzwj@digitalchina.com> Co-authored-by: Kalo Chin <91766386+fdb02983rhy@users.noreply.github.com> Co-authored-by: Katy Tao <34019945+KatyTao@users.noreply.github.com> Co-authored-by: depy <42985524+h4ckdepy@users.noreply.github.com> Co-authored-by: 胡春东 <gycm520@gmail.com> Co-authored-by: Junjie.M <118170653@qq.com> Co-authored-by: MuYu <mr.muzea@gmail.com> Co-authored-by: Naoki Takashima <39912547+takatea@users.noreply.github.com> Co-authored-by: Summer-Gu <37869445+gubinjie@users.noreply.github.com> Co-authored-by: Fei He <droxer.he@gmail.com> Co-authored-by: ybalbert001 <120714773+ybalbert001@users.noreply.github.com> Co-authored-by: Yuanbo Li <ybalbert@amazon.com> Co-authored-by: douxc <7553076+douxc@users.noreply.github.com> Co-authored-by: liuzhenghua <1090179900@qq.com> Co-authored-by: Wu Jiayang <62842862+Wu-Jiayang@users.noreply.github.com> Co-authored-by: Your Name <you@example.com> Co-authored-by: kimjion <45935338+kimjion@users.noreply.github.com> Co-authored-by: AugNSo <song.tiankai@icloud.com> Co-authored-by: llinvokerl <38915183+llinvokerl@users.noreply.github.com> Co-authored-by: liusurong.lsr <liusurong.lsr@alibaba-inc.com> Co-authored-by: Vasu Negi <vasu-negi@users.noreply.github.com> Co-authored-by: Hundredwz <1808096180@qq.com> Co-authored-by: Xiyuan Chen <52963600+GareArc@users.noreply.github.com>
This commit is contained in:
@@ -73,7 +73,6 @@ from .task import CeleryTask, CeleryTaskSet
|
||||
from .tools import (
|
||||
ApiToolProvider,
|
||||
BuiltinToolProvider,
|
||||
PublishedAppTool,
|
||||
ToolConversationVariables,
|
||||
ToolFile,
|
||||
ToolLabelBinding,
|
||||
@@ -150,7 +149,6 @@ __all__ = [
|
||||
"ProviderOrder",
|
||||
"ProviderQuotaType",
|
||||
"ProviderType",
|
||||
"PublishedAppTool",
|
||||
"RecommendedApp",
|
||||
"SavedMessage",
|
||||
"Site",
|
||||
|
||||
@@ -5,6 +5,8 @@ from flask_login import UserMixin # type: ignore
|
||||
from sqlalchemy import func
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from models.base import Base
|
||||
|
||||
from .engine import db
|
||||
from .types import StringUUID
|
||||
|
||||
@@ -17,7 +19,7 @@ class AccountStatus(enum.StrEnum):
|
||||
CLOSED = "closed"
|
||||
|
||||
|
||||
class Account(UserMixin, db.Model): # type: ignore[name-defined]
|
||||
class Account(UserMixin, Base):
|
||||
__tablename__ = "accounts"
|
||||
__table_args__ = (db.PrimaryKeyConstraint("id", name="account_pkey"), db.Index("account_email_idx", "email"))
|
||||
|
||||
@@ -54,8 +56,8 @@ class Account(UserMixin, db.Model): # type: ignore[name-defined]
|
||||
if ta:
|
||||
tenant.current_role = ta.role
|
||||
else:
|
||||
# FIXME: fix the type error later, because the type is important maybe cause some bugs
|
||||
tenant = None # type: ignore
|
||||
|
||||
self._current_tenant = tenant
|
||||
|
||||
@property
|
||||
@@ -78,7 +80,7 @@ class Account(UserMixin, db.Model): # type: ignore[name-defined]
|
||||
tenant.current_role = ta.role
|
||||
else:
|
||||
tenant = None
|
||||
except:
|
||||
except Exception:
|
||||
tenant = None
|
||||
|
||||
self._current_tenant = tenant
|
||||
@@ -102,6 +104,7 @@ class Account(UserMixin, db.Model): # type: ignore[name-defined]
|
||||
return db.session.query(Account).filter(Account.id == account_integrate.account_id).one_or_none()
|
||||
return None
|
||||
|
||||
# check current_user.current_tenant.current_role in ['admin', 'owner']
|
||||
@property
|
||||
def is_admin_or_owner(self):
|
||||
return TenantAccountRole.is_privileged_role(self._current_tenant.current_role)
|
||||
@@ -137,6 +140,8 @@ class TenantAccountRole(enum.StrEnum):
|
||||
|
||||
@staticmethod
|
||||
def is_valid_role(role: str) -> bool:
|
||||
if not role:
|
||||
return False
|
||||
return role in {
|
||||
TenantAccountRole.OWNER,
|
||||
TenantAccountRole.ADMIN,
|
||||
@@ -147,14 +152,20 @@ class TenantAccountRole(enum.StrEnum):
|
||||
|
||||
@staticmethod
|
||||
def is_privileged_role(role: str) -> bool:
|
||||
if not role:
|
||||
return False
|
||||
return role in {TenantAccountRole.OWNER, TenantAccountRole.ADMIN}
|
||||
|
||||
@staticmethod
|
||||
def is_admin_role(role: str) -> bool:
|
||||
if not role:
|
||||
return False
|
||||
return role == TenantAccountRole.ADMIN
|
||||
|
||||
@staticmethod
|
||||
def is_non_owner_role(role: str) -> bool:
|
||||
if not role:
|
||||
return False
|
||||
return role in {
|
||||
TenantAccountRole.ADMIN,
|
||||
TenantAccountRole.EDITOR,
|
||||
@@ -164,10 +175,14 @@ class TenantAccountRole(enum.StrEnum):
|
||||
|
||||
@staticmethod
|
||||
def is_editing_role(role: str) -> bool:
|
||||
if not role:
|
||||
return False
|
||||
return role in {TenantAccountRole.OWNER, TenantAccountRole.ADMIN, TenantAccountRole.EDITOR}
|
||||
|
||||
@staticmethod
|
||||
def is_dataset_edit_role(role: str) -> bool:
|
||||
if not role:
|
||||
return False
|
||||
return role in {
|
||||
TenantAccountRole.OWNER,
|
||||
TenantAccountRole.ADMIN,
|
||||
@@ -264,4 +279,29 @@ class InvitationCode(db.Model): # type: ignore[name-defined]
|
||||
used_by_tenant_id = db.Column(StringUUID)
|
||||
used_by_account_id = db.Column(StringUUID)
|
||||
deprecated_at = db.Column(db.DateTime)
|
||||
created_at = db.Column(db.DateTime, nullable=False, server_default=func.current_timestamp())
|
||||
created_at = db.Column(db.DateTime, nullable=False, server_default=db.text("CURRENT_TIMESTAMP(0)"))
|
||||
|
||||
|
||||
class TenantPluginPermission(Base):
|
||||
class InstallPermission(enum.StrEnum):
|
||||
EVERYONE = "everyone"
|
||||
ADMINS = "admins"
|
||||
NOBODY = "noone"
|
||||
|
||||
class DebugPermission(enum.StrEnum):
|
||||
EVERYONE = "everyone"
|
||||
ADMINS = "admins"
|
||||
NOBODY = "noone"
|
||||
|
||||
__tablename__ = "account_plugin_permissions"
|
||||
__table_args__ = (
|
||||
db.PrimaryKeyConstraint("id", name="account_plugin_permission_pkey"),
|
||||
db.UniqueConstraint("tenant_id", name="unique_tenant_plugin"),
|
||||
)
|
||||
|
||||
id: Mapped[str] = mapped_column(StringUUID, server_default=db.text("uuid_generate_v4()"))
|
||||
tenant_id: Mapped[str] = mapped_column(StringUUID, nullable=False)
|
||||
install_permission: Mapped[InstallPermission] = mapped_column(
|
||||
db.String(16), nullable=False, server_default="everyone"
|
||||
)
|
||||
debug_permission: Mapped[DebugPermission] = mapped_column(db.String(16), nullable=False, server_default="noone")
|
||||
|
||||
5
api/models/base.py
Normal file
5
api/models/base.py
Normal file
@@ -0,0 +1,5 @@
|
||||
from sqlalchemy.orm import declarative_base
|
||||
|
||||
from models.engine import metadata
|
||||
|
||||
Base = declarative_base(metadata=metadata)
|
||||
@@ -584,6 +584,10 @@ class DocumentSegment(db.Model): # type: ignore[name-defined]
|
||||
else:
|
||||
return []
|
||||
|
||||
@property
|
||||
def sign_content(self):
|
||||
return self.get_sign_content()
|
||||
|
||||
def get_sign_content(self):
|
||||
signed_urls = []
|
||||
text = self.content
|
||||
|
||||
@@ -3,20 +3,31 @@ import re
|
||||
import uuid
|
||||
from collections.abc import Mapping
|
||||
from datetime import datetime
|
||||
from enum import Enum, StrEnum
|
||||
from typing import TYPE_CHECKING, Any, Literal, Optional, cast
|
||||
from enum import Enum
|
||||
from typing import TYPE_CHECKING, Optional
|
||||
|
||||
from core.plugin.entities.plugin import GenericProviderID
|
||||
from core.tools.entities.tool_entities import ToolProviderType
|
||||
from services.plugin.plugin_service import PluginService
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from models.workflow import Workflow
|
||||
|
||||
from enum import StrEnum
|
||||
from typing import TYPE_CHECKING, Any, Literal, cast
|
||||
|
||||
import sqlalchemy as sa
|
||||
from flask import request
|
||||
from flask_login import UserMixin # type: ignore
|
||||
from sqlalchemy import Float, func, text
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
from sqlalchemy import Float, Index, PrimaryKeyConstraint, func, text
|
||||
from sqlalchemy.orm import Mapped, Session, mapped_column
|
||||
|
||||
from configs import dify_config
|
||||
from core.file import FILE_MODEL_IDENTITY, File, FileTransferMethod, FileType
|
||||
from core.file import helpers as file_helpers
|
||||
from core.file.tool_file_parser import ToolFileParser
|
||||
from libs.helper import generate_string
|
||||
from models.base import Base
|
||||
from models.enums import CreatedByRole
|
||||
from models.workflow import WorkflowRunStatus
|
||||
|
||||
@@ -28,7 +39,7 @@ if TYPE_CHECKING:
|
||||
from .workflow import Workflow
|
||||
|
||||
|
||||
class DifySetup(db.Model): # type: ignore[name-defined]
|
||||
class DifySetup(Base):
|
||||
__tablename__ = "dify_setups"
|
||||
__table_args__ = (db.PrimaryKeyConstraint("version", name="dify_setup_pkey"),)
|
||||
|
||||
@@ -63,7 +74,7 @@ class IconType(Enum):
|
||||
EMOJI = "emoji"
|
||||
|
||||
|
||||
class App(db.Model): # type: ignore[name-defined]
|
||||
class App(Base):
|
||||
__tablename__ = "apps"
|
||||
__table_args__ = (db.PrimaryKeyConstraint("id", name="app_pkey"), db.Index("app_tenant_id_idx", "tenant_id"))
|
||||
|
||||
@@ -141,7 +152,8 @@ class App(db.Model): # type: ignore[name-defined]
|
||||
return False
|
||||
if not app_model_config.agent_mode:
|
||||
return False
|
||||
if self.app_model_config.agent_mode_dict.get("enabled", False) and self.app_model_config.agent_mode_dict.get(
|
||||
|
||||
if app_model_config.agent_mode_dict.get("enabled", False) and app_model_config.agent_mode_dict.get(
|
||||
"strategy", ""
|
||||
) in {"function_call", "react"}:
|
||||
self.mode = AppMode.AGENT_CHAT.value
|
||||
@@ -158,47 +170,113 @@ class App(db.Model): # type: ignore[name-defined]
|
||||
|
||||
@property
|
||||
def deleted_tools(self) -> list:
|
||||
from core.tools.tool_manager import ToolManager
|
||||
|
||||
# get agent mode tools
|
||||
app_model_config = self.app_model_config
|
||||
if not app_model_config:
|
||||
return []
|
||||
|
||||
if not app_model_config.agent_mode:
|
||||
return []
|
||||
|
||||
agent_mode = app_model_config.agent_mode_dict
|
||||
tools = agent_mode.get("tools", [])
|
||||
|
||||
provider_ids = []
|
||||
api_provider_ids: list[str] = []
|
||||
builtin_provider_ids: list[GenericProviderID] = []
|
||||
|
||||
for tool in tools:
|
||||
keys = list(tool.keys())
|
||||
if len(keys) >= 4:
|
||||
provider_type = tool.get("provider_type", "")
|
||||
provider_id = tool.get("provider_id", "")
|
||||
if provider_type == "api":
|
||||
# check if provider id is a uuid string, if not, skip
|
||||
if provider_type == ToolProviderType.API.value:
|
||||
try:
|
||||
uuid.UUID(provider_id)
|
||||
except Exception:
|
||||
continue
|
||||
provider_ids.append(provider_id)
|
||||
api_provider_ids.append(provider_id)
|
||||
if provider_type == ToolProviderType.BUILT_IN.value:
|
||||
try:
|
||||
# check if it's hardcoded
|
||||
try:
|
||||
ToolManager.get_hardcoded_provider(provider_id)
|
||||
is_hardcoded = True
|
||||
except Exception:
|
||||
is_hardcoded = False
|
||||
|
||||
if not provider_ids:
|
||||
provider_id = GenericProviderID(provider_id, is_hardcoded)
|
||||
except Exception:
|
||||
continue
|
||||
|
||||
builtin_provider_ids.append(provider_id)
|
||||
|
||||
if not api_provider_ids and not builtin_provider_ids:
|
||||
return []
|
||||
|
||||
api_providers = db.session.execute(
|
||||
text("SELECT id FROM tool_api_providers WHERE id IN :provider_ids"), {"provider_ids": tuple(provider_ids)}
|
||||
).fetchall()
|
||||
with Session(db.engine) as session:
|
||||
if api_provider_ids:
|
||||
existing_api_providers = [
|
||||
api_provider.id
|
||||
for api_provider in session.execute(
|
||||
text("SELECT id FROM tool_api_providers WHERE id IN :provider_ids"),
|
||||
{"provider_ids": tuple(api_provider_ids)},
|
||||
).fetchall()
|
||||
]
|
||||
else:
|
||||
existing_api_providers = []
|
||||
|
||||
if builtin_provider_ids:
|
||||
# get the non-hardcoded builtin providers
|
||||
non_hardcoded_builtin_providers = [
|
||||
provider_id for provider_id in builtin_provider_ids if not provider_id.is_hardcoded
|
||||
]
|
||||
if non_hardcoded_builtin_providers:
|
||||
existence = list(PluginService.check_tools_existence(self.tenant_id, non_hardcoded_builtin_providers))
|
||||
else:
|
||||
existence = []
|
||||
# add the hardcoded builtin providers
|
||||
existence.extend([True] * (len(builtin_provider_ids) - len(non_hardcoded_builtin_providers)))
|
||||
builtin_provider_ids = non_hardcoded_builtin_providers + [
|
||||
provider_id for provider_id in builtin_provider_ids if provider_id.is_hardcoded
|
||||
]
|
||||
else:
|
||||
existence = []
|
||||
|
||||
existing_builtin_providers = {
|
||||
provider_id.provider_name: existence[i] for i, provider_id in enumerate(builtin_provider_ids)
|
||||
}
|
||||
|
||||
deleted_tools = []
|
||||
current_api_provider_ids = [str(api_provider.id) for api_provider in api_providers]
|
||||
|
||||
for tool in tools:
|
||||
keys = list(tool.keys())
|
||||
if len(keys) >= 4:
|
||||
provider_type = tool.get("provider_type", "")
|
||||
provider_id = tool.get("provider_id", "")
|
||||
if provider_type == "api" and provider_id not in current_api_provider_ids:
|
||||
deleted_tools.append(tool["tool_name"])
|
||||
|
||||
if provider_type == ToolProviderType.API.value:
|
||||
if provider_id not in existing_api_providers:
|
||||
deleted_tools.append(
|
||||
{
|
||||
"type": ToolProviderType.API.value,
|
||||
"tool_name": tool["tool_name"],
|
||||
"provider_id": provider_id,
|
||||
}
|
||||
)
|
||||
|
||||
if provider_type == ToolProviderType.BUILT_IN.value:
|
||||
generic_provider_id = GenericProviderID(provider_id)
|
||||
|
||||
if not existing_builtin_providers[generic_provider_id.provider_name]:
|
||||
deleted_tools.append(
|
||||
{
|
||||
"type": ToolProviderType.BUILT_IN.value,
|
||||
"tool_name": tool["tool_name"],
|
||||
"provider_id": provider_id, # use the original one
|
||||
}
|
||||
)
|
||||
|
||||
return deleted_tools
|
||||
|
||||
@@ -219,7 +297,7 @@ class App(db.Model): # type: ignore[name-defined]
|
||||
return tags or []
|
||||
|
||||
|
||||
class AppModelConfig(db.Model): # type: ignore[name-defined]
|
||||
class AppModelConfig(Base):
|
||||
__tablename__ = "app_model_configs"
|
||||
__table_args__ = (db.PrimaryKeyConstraint("id", name="app_model_config_pkey"), db.Index("app_app_id_idx", "app_id"))
|
||||
|
||||
@@ -292,6 +370,9 @@ class AppModelConfig(db.Model): # type: ignore[name-defined]
|
||||
)
|
||||
if annotation_setting:
|
||||
collection_binding_detail = annotation_setting.collection_binding_detail
|
||||
if not collection_binding_detail:
|
||||
raise ValueError("Collection binding detail not found")
|
||||
|
||||
return {
|
||||
"id": annotation_setting.id,
|
||||
"enabled": True,
|
||||
@@ -322,7 +403,7 @@ class AppModelConfig(db.Model): # type: ignore[name-defined]
|
||||
return json.loads(self.external_data_tools) if self.external_data_tools else []
|
||||
|
||||
@property
|
||||
def user_input_form_list(self) -> list[dict]:
|
||||
def user_input_form_list(self):
|
||||
return json.loads(self.user_input_form) if self.user_input_form else []
|
||||
|
||||
@property
|
||||
@@ -466,7 +547,7 @@ class AppModelConfig(db.Model): # type: ignore[name-defined]
|
||||
return new_app_model_config
|
||||
|
||||
|
||||
class RecommendedApp(db.Model): # type: ignore[name-defined]
|
||||
class RecommendedApp(Base):
|
||||
__tablename__ = "recommended_apps"
|
||||
__table_args__ = (
|
||||
db.PrimaryKeyConstraint("id", name="recommended_app_pkey"),
|
||||
@@ -494,7 +575,7 @@ class RecommendedApp(db.Model): # type: ignore[name-defined]
|
||||
return app
|
||||
|
||||
|
||||
class InstalledApp(db.Model): # type: ignore[name-defined]
|
||||
class InstalledApp(Base):
|
||||
__tablename__ = "installed_apps"
|
||||
__table_args__ = (
|
||||
db.PrimaryKeyConstraint("id", name="installed_app_pkey"),
|
||||
@@ -523,7 +604,7 @@ class InstalledApp(db.Model): # type: ignore[name-defined]
|
||||
return tenant
|
||||
|
||||
|
||||
class Conversation(db.Model): # type: ignore[name-defined]
|
||||
class Conversation(Base):
|
||||
__tablename__ = "conversations"
|
||||
__table_args__ = (
|
||||
db.PrimaryKeyConstraint("id", name="conversation_pkey"),
|
||||
@@ -758,16 +839,16 @@ class Conversation(db.Model): # type: ignore[name-defined]
|
||||
return self.override_model_configs is not None
|
||||
|
||||
|
||||
class Message(db.Model): # type: ignore[name-defined]
|
||||
class Message(Base):
|
||||
__tablename__ = "messages"
|
||||
__table_args__ = (
|
||||
db.PrimaryKeyConstraint("id", name="message_pkey"),
|
||||
db.Index("message_app_id_idx", "app_id", "created_at"),
|
||||
db.Index("message_conversation_id_idx", "conversation_id"),
|
||||
db.Index("message_end_user_idx", "app_id", "from_source", "from_end_user_id"),
|
||||
db.Index("message_account_idx", "app_id", "from_source", "from_account_id"),
|
||||
db.Index("message_workflow_run_id_idx", "conversation_id", "workflow_run_id"),
|
||||
db.Index("message_created_at_idx", "created_at"),
|
||||
PrimaryKeyConstraint("id", name="message_pkey"),
|
||||
Index("message_app_id_idx", "app_id", "created_at"),
|
||||
Index("message_conversation_id_idx", "conversation_id"),
|
||||
Index("message_end_user_idx", "app_id", "from_source", "from_end_user_id"),
|
||||
Index("message_account_idx", "app_id", "from_source", "from_account_id"),
|
||||
Index("message_workflow_run_id_idx", "conversation_id", "workflow_run_id"),
|
||||
Index("message_created_at_idx", "created_at"),
|
||||
)
|
||||
|
||||
id: Mapped[str] = mapped_column(StringUUID, server_default=db.text("uuid_generate_v4()"))
|
||||
@@ -1109,7 +1190,7 @@ class Message(db.Model): # type: ignore[name-defined]
|
||||
)
|
||||
|
||||
|
||||
class MessageFeedback(db.Model): # type: ignore[name-defined]
|
||||
class MessageFeedback(Base):
|
||||
__tablename__ = "message_feedbacks"
|
||||
__table_args__ = (
|
||||
db.PrimaryKeyConstraint("id", name="message_feedback_pkey"),
|
||||
@@ -1136,7 +1217,7 @@ class MessageFeedback(db.Model): # type: ignore[name-defined]
|
||||
return account
|
||||
|
||||
|
||||
class MessageFile(db.Model): # type: ignore[name-defined]
|
||||
class MessageFile(Base):
|
||||
__tablename__ = "message_files"
|
||||
__table_args__ = (
|
||||
db.PrimaryKeyConstraint("id", name="message_file_pkey"),
|
||||
@@ -1177,7 +1258,7 @@ class MessageFile(db.Model): # type: ignore[name-defined]
|
||||
created_at: Mapped[datetime] = db.Column(db.DateTime, nullable=False, server_default=func.current_timestamp())
|
||||
|
||||
|
||||
class MessageAnnotation(db.Model): # type: ignore[name-defined]
|
||||
class MessageAnnotation(Base):
|
||||
__tablename__ = "message_annotations"
|
||||
__table_args__ = (
|
||||
db.PrimaryKeyConstraint("id", name="message_annotation_pkey"),
|
||||
@@ -1208,7 +1289,7 @@ class MessageAnnotation(db.Model): # type: ignore[name-defined]
|
||||
return account
|
||||
|
||||
|
||||
class AppAnnotationHitHistory(db.Model): # type: ignore[name-defined]
|
||||
class AppAnnotationHitHistory(Base):
|
||||
__tablename__ = "app_annotation_hit_histories"
|
||||
__table_args__ = (
|
||||
db.PrimaryKeyConstraint("id", name="app_annotation_hit_histories_pkey"),
|
||||
@@ -1246,7 +1327,7 @@ class AppAnnotationHitHistory(db.Model): # type: ignore[name-defined]
|
||||
return account
|
||||
|
||||
|
||||
class AppAnnotationSetting(db.Model): # type: ignore[name-defined]
|
||||
class AppAnnotationSetting(Base):
|
||||
__tablename__ = "app_annotation_settings"
|
||||
__table_args__ = (
|
||||
db.PrimaryKeyConstraint("id", name="app_annotation_settings_pkey"),
|
||||
@@ -1294,7 +1375,7 @@ class AppAnnotationSetting(db.Model): # type: ignore[name-defined]
|
||||
return collection_binding_detail
|
||||
|
||||
|
||||
class OperationLog(db.Model): # type: ignore[name-defined]
|
||||
class OperationLog(Base):
|
||||
__tablename__ = "operation_logs"
|
||||
__table_args__ = (
|
||||
db.PrimaryKeyConstraint("id", name="operation_log_pkey"),
|
||||
@@ -1311,7 +1392,7 @@ class OperationLog(db.Model): # type: ignore[name-defined]
|
||||
updated_at = db.Column(db.DateTime, nullable=False, server_default=func.current_timestamp())
|
||||
|
||||
|
||||
class EndUser(UserMixin, db.Model): # type: ignore[name-defined]
|
||||
class EndUser(Base, UserMixin):
|
||||
__tablename__ = "end_users"
|
||||
__table_args__ = (
|
||||
db.PrimaryKeyConstraint("id", name="end_user_pkey"),
|
||||
@@ -1331,7 +1412,7 @@ class EndUser(UserMixin, db.Model): # type: ignore[name-defined]
|
||||
updated_at = db.Column(db.DateTime, nullable=False, server_default=func.current_timestamp())
|
||||
|
||||
|
||||
class Site(db.Model): # type: ignore[name-defined]
|
||||
class Site(Base):
|
||||
__tablename__ = "sites"
|
||||
__table_args__ = (
|
||||
db.PrimaryKeyConstraint("id", name="site_pkey"),
|
||||
@@ -1388,7 +1469,7 @@ class Site(db.Model): # type: ignore[name-defined]
|
||||
return dify_config.APP_WEB_URL or request.url_root.rstrip("/")
|
||||
|
||||
|
||||
class ApiToken(db.Model): # type: ignore[name-defined]
|
||||
class ApiToken(Base):
|
||||
__tablename__ = "api_tokens"
|
||||
__table_args__ = (
|
||||
db.PrimaryKeyConstraint("id", name="api_token_pkey"),
|
||||
@@ -1414,7 +1495,7 @@ class ApiToken(db.Model): # type: ignore[name-defined]
|
||||
return result
|
||||
|
||||
|
||||
class UploadFile(db.Model): # type: ignore[name-defined]
|
||||
class UploadFile(Base):
|
||||
__tablename__ = "upload_files"
|
||||
__table_args__ = (
|
||||
db.PrimaryKeyConstraint("id", name="upload_file_pkey"),
|
||||
@@ -1476,7 +1557,7 @@ class UploadFile(db.Model): # type: ignore[name-defined]
|
||||
self.source_url = source_url
|
||||
|
||||
|
||||
class ApiRequest(db.Model): # type: ignore[name-defined]
|
||||
class ApiRequest(Base):
|
||||
__tablename__ = "api_requests"
|
||||
__table_args__ = (
|
||||
db.PrimaryKeyConstraint("id", name="api_request_pkey"),
|
||||
@@ -1493,7 +1574,7 @@ class ApiRequest(db.Model): # type: ignore[name-defined]
|
||||
created_at = db.Column(db.DateTime, nullable=False, server_default=func.current_timestamp())
|
||||
|
||||
|
||||
class MessageChain(db.Model): # type: ignore[name-defined]
|
||||
class MessageChain(Base):
|
||||
__tablename__ = "message_chains"
|
||||
__table_args__ = (
|
||||
db.PrimaryKeyConstraint("id", name="message_chain_pkey"),
|
||||
@@ -1508,7 +1589,7 @@ class MessageChain(db.Model): # type: ignore[name-defined]
|
||||
created_at = db.Column(db.DateTime, nullable=False, server_default=db.func.current_timestamp())
|
||||
|
||||
|
||||
class MessageAgentThought(db.Model): # type: ignore[name-defined]
|
||||
class MessageAgentThought(Base):
|
||||
__tablename__ = "message_agent_thoughts"
|
||||
__table_args__ = (
|
||||
db.PrimaryKeyConstraint("id", name="message_agent_thought_pkey"),
|
||||
@@ -1563,7 +1644,7 @@ class MessageAgentThought(db.Model): # type: ignore[name-defined]
|
||||
return cast(dict, json.loads(self.tool_labels_str))
|
||||
else:
|
||||
return {}
|
||||
except Exception as e:
|
||||
except Exception:
|
||||
return {}
|
||||
|
||||
@property
|
||||
@@ -1573,7 +1654,7 @@ class MessageAgentThought(db.Model): # type: ignore[name-defined]
|
||||
return cast(dict, json.loads(self.tool_meta_str))
|
||||
else:
|
||||
return {}
|
||||
except Exception as e:
|
||||
except Exception:
|
||||
return {}
|
||||
|
||||
@property
|
||||
@@ -1594,11 +1675,11 @@ class MessageAgentThought(db.Model): # type: ignore[name-defined]
|
||||
return result
|
||||
else:
|
||||
return {tool: {} for tool in tools}
|
||||
except Exception as e:
|
||||
except Exception:
|
||||
return {}
|
||||
|
||||
@property
|
||||
def tool_outputs_dict(self) -> dict:
|
||||
def tool_outputs_dict(self):
|
||||
tools = self.tools
|
||||
try:
|
||||
if self.observation:
|
||||
@@ -1615,14 +1696,14 @@ class MessageAgentThought(db.Model): # type: ignore[name-defined]
|
||||
return result
|
||||
else:
|
||||
return {tool: {} for tool in tools}
|
||||
except Exception as e:
|
||||
except Exception:
|
||||
if self.observation:
|
||||
return dict.fromkeys(tools, self.observation)
|
||||
else:
|
||||
return {}
|
||||
|
||||
|
||||
class DatasetRetrieverResource(db.Model): # type: ignore[name-defined]
|
||||
class DatasetRetrieverResource(Base):
|
||||
__tablename__ = "dataset_retriever_resources"
|
||||
__table_args__ = (
|
||||
db.PrimaryKeyConstraint("id", name="dataset_retriever_resource_pkey"),
|
||||
@@ -1649,7 +1730,7 @@ class DatasetRetrieverResource(db.Model): # type: ignore[name-defined]
|
||||
created_at = db.Column(db.DateTime, nullable=False, server_default=db.func.current_timestamp())
|
||||
|
||||
|
||||
class Tag(db.Model): # type: ignore[name-defined]
|
||||
class Tag(Base):
|
||||
__tablename__ = "tags"
|
||||
__table_args__ = (
|
||||
db.PrimaryKeyConstraint("id", name="tag_pkey"),
|
||||
@@ -1667,7 +1748,7 @@ class Tag(db.Model): # type: ignore[name-defined]
|
||||
created_at = db.Column(db.DateTime, nullable=False, server_default=func.current_timestamp())
|
||||
|
||||
|
||||
class TagBinding(db.Model): # type: ignore[name-defined]
|
||||
class TagBinding(Base):
|
||||
__tablename__ = "tag_bindings"
|
||||
__table_args__ = (
|
||||
db.PrimaryKeyConstraint("id", name="tag_binding_pkey"),
|
||||
@@ -1683,7 +1764,7 @@ class TagBinding(db.Model): # type: ignore[name-defined]
|
||||
created_at = db.Column(db.DateTime, nullable=False, server_default=func.current_timestamp())
|
||||
|
||||
|
||||
class TraceAppConfig(db.Model): # type: ignore[name-defined]
|
||||
class TraceAppConfig(Base):
|
||||
__tablename__ = "trace_app_config"
|
||||
__table_args__ = (
|
||||
db.PrimaryKeyConstraint("id", name="tracing_app_config_pkey"),
|
||||
|
||||
@@ -2,6 +2,8 @@ from enum import Enum
|
||||
|
||||
from sqlalchemy import func
|
||||
|
||||
from models.base import Base
|
||||
|
||||
from .engine import db
|
||||
from .types import StringUUID
|
||||
|
||||
@@ -36,7 +38,7 @@ class ProviderQuotaType(Enum):
|
||||
raise ValueError(f"No matching enum found for value '{value}'")
|
||||
|
||||
|
||||
class Provider(db.Model): # type: ignore[name-defined]
|
||||
class Provider(Base):
|
||||
"""
|
||||
Provider model representing the API providers and their configurations.
|
||||
"""
|
||||
@@ -89,7 +91,7 @@ class Provider(db.Model): # type: ignore[name-defined]
|
||||
return self.is_valid and self.token_is_set
|
||||
|
||||
|
||||
class ProviderModel(db.Model): # type: ignore[name-defined]
|
||||
class ProviderModel(Base):
|
||||
"""
|
||||
Provider model representing the API provider_models and their configurations.
|
||||
"""
|
||||
@@ -114,7 +116,7 @@ class ProviderModel(db.Model): # type: ignore[name-defined]
|
||||
updated_at = db.Column(db.DateTime, nullable=False, server_default=func.current_timestamp())
|
||||
|
||||
|
||||
class TenantDefaultModel(db.Model): # type: ignore[name-defined]
|
||||
class TenantDefaultModel(Base):
|
||||
__tablename__ = "tenant_default_models"
|
||||
__table_args__ = (
|
||||
db.PrimaryKeyConstraint("id", name="tenant_default_model_pkey"),
|
||||
@@ -130,7 +132,7 @@ class TenantDefaultModel(db.Model): # type: ignore[name-defined]
|
||||
updated_at = db.Column(db.DateTime, nullable=False, server_default=func.current_timestamp())
|
||||
|
||||
|
||||
class TenantPreferredModelProvider(db.Model): # type: ignore[name-defined]
|
||||
class TenantPreferredModelProvider(Base):
|
||||
__tablename__ = "tenant_preferred_model_providers"
|
||||
__table_args__ = (
|
||||
db.PrimaryKeyConstraint("id", name="tenant_preferred_model_provider_pkey"),
|
||||
@@ -145,7 +147,7 @@ class TenantPreferredModelProvider(db.Model): # type: ignore[name-defined]
|
||||
updated_at = db.Column(db.DateTime, nullable=False, server_default=func.current_timestamp())
|
||||
|
||||
|
||||
class ProviderOrder(db.Model): # type: ignore[name-defined]
|
||||
class ProviderOrder(Base):
|
||||
__tablename__ = "provider_orders"
|
||||
__table_args__ = (
|
||||
db.PrimaryKeyConstraint("id", name="provider_order_pkey"),
|
||||
@@ -170,7 +172,7 @@ class ProviderOrder(db.Model): # type: ignore[name-defined]
|
||||
updated_at = db.Column(db.DateTime, nullable=False, server_default=func.current_timestamp())
|
||||
|
||||
|
||||
class ProviderModelSetting(db.Model): # type: ignore[name-defined]
|
||||
class ProviderModelSetting(Base):
|
||||
"""
|
||||
Provider model settings for record the model enabled status and load balancing status.
|
||||
"""
|
||||
@@ -192,7 +194,7 @@ class ProviderModelSetting(db.Model): # type: ignore[name-defined]
|
||||
updated_at = db.Column(db.DateTime, nullable=False, server_default=func.current_timestamp())
|
||||
|
||||
|
||||
class LoadBalancingModelConfig(db.Model): # type: ignore[name-defined]
|
||||
class LoadBalancingModelConfig(Base):
|
||||
"""
|
||||
Configurations for load balancing models.
|
||||
"""
|
||||
|
||||
@@ -3,6 +3,8 @@ import json
|
||||
from sqlalchemy import func
|
||||
from sqlalchemy.dialects.postgresql import JSONB
|
||||
|
||||
from models.base import Base
|
||||
|
||||
from .engine import db
|
||||
from .types import StringUUID
|
||||
|
||||
@@ -25,7 +27,7 @@ class DataSourceOauthBinding(db.Model): # type: ignore[name-defined]
|
||||
disabled = db.Column(db.Boolean, nullable=True, server_default=db.text("false"))
|
||||
|
||||
|
||||
class DataSourceApiKeyAuthBinding(db.Model): # type: ignore[name-defined]
|
||||
class DataSourceApiKeyAuthBinding(Base):
|
||||
__tablename__ = "data_source_api_key_auth_bindings"
|
||||
__table_args__ = (
|
||||
db.PrimaryKeyConstraint("id", name="data_source_api_key_auth_binding_pkey"),
|
||||
|
||||
@@ -2,10 +2,12 @@ from datetime import UTC, datetime
|
||||
|
||||
from celery import states # type: ignore
|
||||
|
||||
from models.base import Base
|
||||
|
||||
from .engine import db
|
||||
|
||||
|
||||
class CeleryTask(db.Model): # type: ignore[name-defined]
|
||||
class CeleryTask(Base):
|
||||
"""Task result/status."""
|
||||
|
||||
__tablename__ = "celery_taskmeta"
|
||||
@@ -29,7 +31,7 @@ class CeleryTask(db.Model): # type: ignore[name-defined]
|
||||
queue = db.Column(db.String(155), nullable=True)
|
||||
|
||||
|
||||
class CeleryTaskSet(db.Model): # type: ignore[name-defined]
|
||||
class CeleryTaskSet(Base):
|
||||
"""TaskSet result."""
|
||||
|
||||
__tablename__ = "celery_tasksetmeta"
|
||||
|
||||
@@ -1,20 +1,23 @@
|
||||
import json
|
||||
from typing import Any, Optional
|
||||
from datetime import datetime
|
||||
from typing import Any, Optional, cast
|
||||
|
||||
import sqlalchemy as sa
|
||||
from deprecated import deprecated
|
||||
from sqlalchemy import ForeignKey, func
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from core.tools.entities.common_entities import I18nObject
|
||||
from core.tools.entities.tool_bundle import ApiToolBundle
|
||||
from core.tools.entities.tool_entities import ApiProviderSchemaType, WorkflowToolParameterConfiguration
|
||||
from models.base import Base
|
||||
|
||||
from .engine import db
|
||||
from .model import Account, App, Tenant
|
||||
from .types import StringUUID
|
||||
|
||||
|
||||
class BuiltinToolProvider(db.Model): # type: ignore[name-defined]
|
||||
class BuiltinToolProvider(Base):
|
||||
"""
|
||||
This table stores the tool provider information for built-in tools for each tenant.
|
||||
"""
|
||||
@@ -27,66 +30,28 @@ class BuiltinToolProvider(db.Model): # type: ignore[name-defined]
|
||||
)
|
||||
|
||||
# id of the tool provider
|
||||
id = db.Column(StringUUID, server_default=db.text("uuid_generate_v4()"))
|
||||
id: Mapped[str] = mapped_column(StringUUID, server_default=db.text("uuid_generate_v4()"))
|
||||
# id of the tenant
|
||||
tenant_id = db.Column(StringUUID, nullable=True)
|
||||
tenant_id: Mapped[str] = mapped_column(StringUUID, nullable=True)
|
||||
# who created this tool provider
|
||||
user_id = db.Column(StringUUID, nullable=False)
|
||||
user_id: Mapped[str] = mapped_column(StringUUID, nullable=False)
|
||||
# name of the tool provider
|
||||
provider = db.Column(db.String(40), nullable=False)
|
||||
provider: Mapped[str] = mapped_column(db.String(256), nullable=False)
|
||||
# credential of the tool provider
|
||||
encrypted_credentials = db.Column(db.Text, nullable=True)
|
||||
created_at = db.Column(db.DateTime, nullable=False, server_default=func.current_timestamp())
|
||||
updated_at = db.Column(db.DateTime, nullable=False, server_default=func.current_timestamp())
|
||||
encrypted_credentials: Mapped[str] = mapped_column(db.Text, nullable=True)
|
||||
created_at: Mapped[datetime] = mapped_column(
|
||||
db.DateTime, nullable=False, server_default=db.text("CURRENT_TIMESTAMP(0)")
|
||||
)
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
db.DateTime, nullable=False, server_default=db.text("CURRENT_TIMESTAMP(0)")
|
||||
)
|
||||
|
||||
@property
|
||||
def credentials(self) -> dict:
|
||||
return dict(json.loads(self.encrypted_credentials))
|
||||
return cast(dict, json.loads(self.encrypted_credentials))
|
||||
|
||||
|
||||
class PublishedAppTool(db.Model): # type: ignore[name-defined]
|
||||
"""
|
||||
The table stores the apps published as a tool for each person.
|
||||
"""
|
||||
|
||||
__tablename__ = "tool_published_apps"
|
||||
__table_args__ = (
|
||||
db.PrimaryKeyConstraint("id", name="published_app_tool_pkey"),
|
||||
db.UniqueConstraint("app_id", "user_id", name="unique_published_app_tool"),
|
||||
)
|
||||
|
||||
# id of the tool provider
|
||||
id = db.Column(StringUUID, server_default=db.text("uuid_generate_v4()"))
|
||||
# id of the app
|
||||
app_id = db.Column(StringUUID, ForeignKey("apps.id"), nullable=False)
|
||||
# who published this tool
|
||||
user_id = db.Column(StringUUID, nullable=False)
|
||||
# description of the tool, stored in i18n format, for human
|
||||
description = db.Column(db.Text, nullable=False)
|
||||
# llm_description of the tool, for LLM
|
||||
llm_description = db.Column(db.Text, nullable=False)
|
||||
# query description, query will be seem as a parameter of the tool,
|
||||
# to describe this parameter to llm, we need this field
|
||||
query_description = db.Column(db.Text, nullable=False)
|
||||
# query name, the name of the query parameter
|
||||
query_name = db.Column(db.String(40), nullable=False)
|
||||
# name of the tool provider
|
||||
tool_name = db.Column(db.String(40), nullable=False)
|
||||
# author
|
||||
author = db.Column(db.String(40), nullable=False)
|
||||
created_at = db.Column(db.DateTime, nullable=False, server_default=func.current_timestamp())
|
||||
updated_at = db.Column(db.DateTime, nullable=False, server_default=func.current_timestamp())
|
||||
|
||||
@property
|
||||
def description_i18n(self) -> I18nObject:
|
||||
return I18nObject(**json.loads(self.description))
|
||||
|
||||
@property
|
||||
def app(self):
|
||||
return db.session.query(App).filter(App.id == self.app_id).first()
|
||||
|
||||
|
||||
class ApiToolProvider(db.Model): # type: ignore[name-defined]
|
||||
class ApiToolProvider(Base):
|
||||
"""
|
||||
The table stores the api providers.
|
||||
"""
|
||||
@@ -120,8 +85,8 @@ class ApiToolProvider(db.Model): # type: ignore[name-defined]
|
||||
# custom_disclaimer
|
||||
custom_disclaimer: Mapped[str] = mapped_column(sa.TEXT, default="")
|
||||
|
||||
created_at = db.Column(db.DateTime, nullable=False, server_default=func.current_timestamp())
|
||||
updated_at = db.Column(db.DateTime, nullable=False, server_default=func.current_timestamp())
|
||||
created_at: Mapped[datetime] = mapped_column(db.DateTime, nullable=False, server_default=func.current_timestamp())
|
||||
updated_at: Mapped[datetime] = mapped_column(db.DateTime, nullable=False, server_default=func.current_timestamp())
|
||||
|
||||
@property
|
||||
def schema_type(self) -> ApiProviderSchemaType:
|
||||
@@ -144,7 +109,7 @@ class ApiToolProvider(db.Model): # type: ignore[name-defined]
|
||||
return db.session.query(Tenant).filter(Tenant.id == self.tenant_id).first()
|
||||
|
||||
|
||||
class ToolLabelBinding(db.Model): # type: ignore[name-defined]
|
||||
class ToolLabelBinding(Base):
|
||||
"""
|
||||
The table stores the labels for tools.
|
||||
"""
|
||||
@@ -155,16 +120,16 @@ class ToolLabelBinding(db.Model): # type: ignore[name-defined]
|
||||
db.UniqueConstraint("tool_id", "label_name", name="unique_tool_label_bind"),
|
||||
)
|
||||
|
||||
id = db.Column(StringUUID, server_default=db.text("uuid_generate_v4()"))
|
||||
id: Mapped[str] = mapped_column(StringUUID, server_default=db.text("uuid_generate_v4()"))
|
||||
# tool id
|
||||
tool_id = db.Column(db.String(64), nullable=False)
|
||||
tool_id: Mapped[str] = mapped_column(db.String(64), nullable=False)
|
||||
# tool type
|
||||
tool_type = db.Column(db.String(40), nullable=False)
|
||||
tool_type: Mapped[str] = mapped_column(db.String(40), nullable=False)
|
||||
# label name
|
||||
label_name = db.Column(db.String(40), nullable=False)
|
||||
label_name: Mapped[str] = mapped_column(db.String(40), nullable=False)
|
||||
|
||||
|
||||
class WorkflowToolProvider(db.Model): # type: ignore[name-defined]
|
||||
class WorkflowToolProvider(Base):
|
||||
"""
|
||||
The table stores the workflow providers.
|
||||
"""
|
||||
@@ -176,30 +141,38 @@ class WorkflowToolProvider(db.Model): # type: ignore[name-defined]
|
||||
db.UniqueConstraint("tenant_id", "app_id", name="unique_workflow_tool_provider_app_id"),
|
||||
)
|
||||
|
||||
id = db.Column(StringUUID, server_default=db.text("uuid_generate_v4()"))
|
||||
id: Mapped[str] = mapped_column(StringUUID, server_default=db.text("uuid_generate_v4()"))
|
||||
# name of the workflow provider
|
||||
name = db.Column(db.String(40), nullable=False)
|
||||
name: Mapped[str] = mapped_column(db.String(40), nullable=False)
|
||||
# label of the workflow provider
|
||||
label = db.Column(db.String(255), nullable=False, server_default="")
|
||||
label: Mapped[str] = mapped_column(db.String(255), nullable=False, server_default="")
|
||||
# icon
|
||||
icon = db.Column(db.String(255), nullable=False)
|
||||
icon: Mapped[str] = mapped_column(db.String(255), nullable=False)
|
||||
# app id of the workflow provider
|
||||
app_id = db.Column(StringUUID, nullable=False)
|
||||
app_id: Mapped[str] = mapped_column(StringUUID, nullable=False)
|
||||
# version of the workflow provider
|
||||
version = db.Column(db.String(255), nullable=False, server_default="")
|
||||
version: Mapped[str] = mapped_column(db.String(255), nullable=False, server_default="")
|
||||
# who created this tool
|
||||
user_id = db.Column(StringUUID, nullable=False)
|
||||
user_id: Mapped[str] = mapped_column(StringUUID, nullable=False)
|
||||
# tenant id
|
||||
tenant_id = db.Column(StringUUID, nullable=False)
|
||||
tenant_id: Mapped[str] = mapped_column(StringUUID, nullable=False)
|
||||
# description of the provider
|
||||
description = db.Column(db.Text, nullable=False)
|
||||
description: Mapped[str] = mapped_column(db.Text, nullable=False)
|
||||
# parameter configuration
|
||||
parameter_configuration = db.Column(db.Text, nullable=False, server_default="[]")
|
||||
parameter_configuration: Mapped[str] = mapped_column(db.Text, nullable=False, server_default="[]")
|
||||
# privacy policy
|
||||
privacy_policy = db.Column(db.String(255), nullable=True, server_default="")
|
||||
privacy_policy: Mapped[str] = mapped_column(db.String(255), nullable=True, server_default="")
|
||||
|
||||
created_at = db.Column(db.DateTime, nullable=False, server_default=func.current_timestamp())
|
||||
updated_at = db.Column(db.DateTime, nullable=False, server_default=func.current_timestamp())
|
||||
created_at: Mapped[datetime] = mapped_column(
|
||||
db.DateTime, nullable=False, server_default=db.text("CURRENT_TIMESTAMP(0)")
|
||||
)
|
||||
updated_at: Mapped[datetime] = mapped_column(
|
||||
db.DateTime, nullable=False, server_default=db.text("CURRENT_TIMESTAMP(0)")
|
||||
)
|
||||
|
||||
@property
|
||||
def schema_type(self) -> ApiProviderSchemaType:
|
||||
return ApiProviderSchemaType.value_of(self.schema_type_str)
|
||||
|
||||
@property
|
||||
def user(self) -> Account | None:
|
||||
@@ -218,7 +191,7 @@ class WorkflowToolProvider(db.Model): # type: ignore[name-defined]
|
||||
return db.session.query(App).filter(App.id == self.app_id).first()
|
||||
|
||||
|
||||
class ToolModelInvoke(db.Model): # type: ignore[name-defined]
|
||||
class ToolModelInvoke(Base):
|
||||
"""
|
||||
store the invoke logs from tool invoke
|
||||
"""
|
||||
@@ -255,7 +228,8 @@ class ToolModelInvoke(db.Model): # type: ignore[name-defined]
|
||||
updated_at = db.Column(db.DateTime, nullable=False, server_default=func.current_timestamp())
|
||||
|
||||
|
||||
class ToolConversationVariables(db.Model): # type: ignore[name-defined]
|
||||
@deprecated
|
||||
class ToolConversationVariables(Base):
|
||||
"""
|
||||
store the conversation variables from tool invoke
|
||||
"""
|
||||
@@ -286,13 +260,70 @@ class ToolConversationVariables(db.Model): # type: ignore[name-defined]
|
||||
return json.loads(self.variables_str)
|
||||
|
||||
|
||||
class ToolFile(db.Model): # type: ignore[name-defined]
|
||||
class ToolFile(Base):
|
||||
"""
|
||||
store the file created by agent
|
||||
"""
|
||||
|
||||
__tablename__ = "tool_files"
|
||||
__table_args__ = (
|
||||
db.PrimaryKeyConstraint("id", name="tool_file_pkey"),
|
||||
db.Index("tool_file_conversation_id_idx", "conversation_id"),
|
||||
)
|
||||
|
||||
id: Mapped[str] = mapped_column(StringUUID, server_default=db.text("uuid_generate_v4()"))
|
||||
# conversation user id
|
||||
user_id: Mapped[str] = mapped_column(StringUUID)
|
||||
# tenant id
|
||||
tenant_id: Mapped[str] = mapped_column(StringUUID)
|
||||
# conversation id
|
||||
conversation_id: Mapped[str] = mapped_column(StringUUID, nullable=True)
|
||||
# file key
|
||||
file_key: Mapped[str] = mapped_column(db.String(255), nullable=False)
|
||||
# mime type
|
||||
mimetype: Mapped[str] = mapped_column(db.String(255), nullable=False)
|
||||
# original url
|
||||
original_url: Mapped[str] = mapped_column(db.String(2048), nullable=True)
|
||||
# name
|
||||
name: Mapped[str] = mapped_column(default="")
|
||||
# size
|
||||
size: Mapped[int] = mapped_column(default=-1)
|
||||
|
||||
|
||||
@deprecated
|
||||
class DeprecatedPublishedAppTool(Base):
|
||||
"""
|
||||
The table stores the apps published as a tool for each person.
|
||||
"""
|
||||
|
||||
__tablename__ = "tool_published_apps"
|
||||
__table_args__ = (
|
||||
db.PrimaryKeyConstraint("id", name="published_app_tool_pkey"),
|
||||
db.UniqueConstraint("app_id", "user_id", name="unique_published_app_tool"),
|
||||
)
|
||||
|
||||
# id of the app
|
||||
app_id = db.Column(StringUUID, ForeignKey("apps.id"), nullable=False)
|
||||
# who published this tool
|
||||
description = db.Column(db.Text, nullable=False)
|
||||
# llm_description of the tool, for LLM
|
||||
llm_description = db.Column(db.Text, nullable=False)
|
||||
# query description, query will be seem as a parameter of the tool,
|
||||
# to describe this parameter to llm, we need this field
|
||||
query_description = db.Column(db.Text, nullable=False)
|
||||
# query name, the name of the query parameter
|
||||
query_name = db.Column(db.String(40), nullable=False)
|
||||
# name of the tool provider
|
||||
tool_name = db.Column(db.String(40), nullable=False)
|
||||
# author
|
||||
author = db.Column(db.String(40), nullable=False)
|
||||
created_at = db.Column(db.DateTime, nullable=False, server_default=db.text("CURRENT_TIMESTAMP(0)"))
|
||||
updated_at = db.Column(db.DateTime, nullable=False, server_default=db.text("CURRENT_TIMESTAMP(0)"))
|
||||
|
||||
@property
|
||||
def description_i18n(self) -> I18nObject:
|
||||
return I18nObject(**json.loads(self.description))
|
||||
|
||||
id = db.Column(StringUUID, server_default=db.text("uuid_generate_v4()"))
|
||||
user_id: Mapped[str] = db.Column(StringUUID, nullable=False)
|
||||
tenant_id: Mapped[str] = db.Column(StringUUID, nullable=False)
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
from sqlalchemy import func
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from models.base import Base
|
||||
|
||||
from .engine import db
|
||||
from .model import Message
|
||||
from .types import StringUUID
|
||||
|
||||
|
||||
class SavedMessage(db.Model): # type: ignore[name-defined]
|
||||
class SavedMessage(Base):
|
||||
__tablename__ = "saved_messages"
|
||||
__table_args__ = (
|
||||
db.PrimaryKeyConstraint("id", name="saved_message_pkey"),
|
||||
@@ -25,7 +27,7 @@ class SavedMessage(db.Model): # type: ignore[name-defined]
|
||||
return db.session.query(Message).filter(Message.id == self.message_id).first()
|
||||
|
||||
|
||||
class PinnedConversation(db.Model): # type: ignore[name-defined]
|
||||
class PinnedConversation(Base):
|
||||
__tablename__ = "pinned_conversations"
|
||||
__table_args__ = (
|
||||
db.PrimaryKeyConstraint("id", name="pinned_conversation_pkey"),
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
import json
|
||||
from collections.abc import Mapping, Sequence
|
||||
from datetime import UTC, datetime
|
||||
from enum import Enum, StrEnum
|
||||
from enum import Enum
|
||||
from typing import TYPE_CHECKING, Any, Optional, Union
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from models.model import AppMode
|
||||
from enum import StrEnum
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy import func
|
||||
from sqlalchemy import Index, PrimaryKeyConstraint, func
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
import contexts
|
||||
@@ -14,6 +19,7 @@ from core.helper import encrypter
|
||||
from core.variables import SecretVariable, Variable
|
||||
from factories import variable_factory
|
||||
from libs import helper
|
||||
from models.base import Base
|
||||
from models.enums import CreatedByRole
|
||||
|
||||
from .account import Account
|
||||
@@ -21,7 +27,7 @@ from .engine import db
|
||||
from .types import StringUUID
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from models.model import AppMode, Message
|
||||
from models.model import AppMode
|
||||
|
||||
|
||||
class WorkflowType(Enum):
|
||||
@@ -59,7 +65,7 @@ class WorkflowType(Enum):
|
||||
return cls.WORKFLOW if app_mode == AppMode.WORKFLOW else cls.CHAT
|
||||
|
||||
|
||||
class Workflow(db.Model): # type: ignore[name-defined]
|
||||
class Workflow(Base):
|
||||
"""
|
||||
Workflow, for `Workflow App` and `Chat App workflow mode`.
|
||||
|
||||
@@ -249,11 +255,13 @@ class Workflow(db.Model): # type: ignore[name-defined]
|
||||
]
|
||||
|
||||
# decrypt secret variables value
|
||||
decrypt_func = (
|
||||
lambda var: var.model_copy(update={"value": encrypter.decrypt_token(tenant_id=tenant_id, token=var.value)})
|
||||
if isinstance(var, SecretVariable)
|
||||
else var
|
||||
)
|
||||
def decrypt_func(var):
|
||||
return (
|
||||
var.model_copy(update={"value": encrypter.decrypt_token(tenant_id=tenant_id, token=var.value)})
|
||||
if isinstance(var, SecretVariable)
|
||||
else var
|
||||
)
|
||||
|
||||
results = list(map(decrypt_func, results))
|
||||
return results
|
||||
|
||||
@@ -277,11 +285,13 @@ class Workflow(db.Model): # type: ignore[name-defined]
|
||||
value[i] = origin_variables_dictionary[variable.id].model_copy(update={"name": variable.name})
|
||||
|
||||
# encrypt secret variables value
|
||||
encrypt_func = (
|
||||
lambda var: var.model_copy(update={"value": encrypter.encrypt_token(tenant_id=tenant_id, token=var.value)})
|
||||
if isinstance(var, SecretVariable)
|
||||
else var
|
||||
)
|
||||
def encrypt_func(var):
|
||||
return (
|
||||
var.model_copy(update={"value": encrypter.encrypt_token(tenant_id=tenant_id, token=var.value)})
|
||||
if isinstance(var, SecretVariable)
|
||||
else var
|
||||
)
|
||||
|
||||
encrypted_vars = list(map(encrypt_func, value))
|
||||
environment_variables_json = json.dumps(
|
||||
{var.name: var.model_dump() for var in encrypted_vars},
|
||||
@@ -347,7 +357,7 @@ class WorkflowRunStatus(StrEnum):
|
||||
raise ValueError(f"invalid workflow run status value {value}")
|
||||
|
||||
|
||||
class WorkflowRun(db.Model): # type: ignore[name-defined]
|
||||
class WorkflowRun(Base):
|
||||
"""
|
||||
Workflow Run
|
||||
|
||||
@@ -439,7 +449,7 @@ class WorkflowRun(db.Model): # type: ignore[name-defined]
|
||||
return json.loads(self.outputs) if self.outputs else {}
|
||||
|
||||
@property
|
||||
def message(self) -> Optional["Message"]:
|
||||
def message(self):
|
||||
from models.model import Message
|
||||
|
||||
return (
|
||||
@@ -549,7 +559,7 @@ class WorkflowNodeExecutionStatus(Enum):
|
||||
raise ValueError(f"invalid workflow node execution status value {value}")
|
||||
|
||||
|
||||
class WorkflowNodeExecution(db.Model): # type: ignore[name-defined]
|
||||
class WorkflowNodeExecution(Base):
|
||||
"""
|
||||
Workflow Node Execution
|
||||
|
||||
@@ -715,7 +725,7 @@ class WorkflowAppLogCreatedFrom(Enum):
|
||||
raise ValueError(f"invalid workflow app log created from value {value}")
|
||||
|
||||
|
||||
class WorkflowAppLog(db.Model): # type: ignore[name-defined]
|
||||
class WorkflowAppLog(Base):
|
||||
"""
|
||||
Workflow App execution log, excluding workflow debugging records.
|
||||
|
||||
@@ -777,15 +787,20 @@ class WorkflowAppLog(db.Model): # type: ignore[name-defined]
|
||||
return db.session.get(EndUser, self.created_by) if created_by_role == CreatedByRole.END_USER else None
|
||||
|
||||
|
||||
class ConversationVariable(db.Model): # type: ignore[name-defined]
|
||||
class ConversationVariable(Base):
|
||||
__tablename__ = "workflow_conversation_variables"
|
||||
__table_args__ = (
|
||||
PrimaryKeyConstraint("id", "conversation_id", name="workflow_conversation_variables_pkey"),
|
||||
Index("workflow__conversation_variables_app_id_idx", "app_id"),
|
||||
Index("workflow__conversation_variables_created_at_idx", "created_at"),
|
||||
)
|
||||
|
||||
id: Mapped[str] = db.Column(StringUUID, primary_key=True)
|
||||
conversation_id: Mapped[str] = db.Column(StringUUID, nullable=False, primary_key=True)
|
||||
app_id: Mapped[str] = db.Column(StringUUID, nullable=False, index=True)
|
||||
data = db.Column(db.Text, nullable=False)
|
||||
created_at = db.Column(db.DateTime, nullable=False, index=True, server_default=func.current_timestamp())
|
||||
updated_at = db.Column(
|
||||
id: Mapped[str] = mapped_column(StringUUID, primary_key=True)
|
||||
conversation_id: Mapped[str] = mapped_column(StringUUID, nullable=False, primary_key=True)
|
||||
app_id: Mapped[str] = mapped_column(StringUUID, nullable=False)
|
||||
data = mapped_column(db.Text, nullable=False)
|
||||
created_at = mapped_column(db.DateTime, nullable=False, server_default=func.current_timestamp())
|
||||
updated_at = mapped_column(
|
||||
db.DateTime, nullable=False, server_default=func.current_timestamp(), onupdate=func.current_timestamp()
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user