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:
Yeuoly
2025-02-17 17:05:13 +08:00
committed by GitHub
parent 222df44d21
commit 403e2d58b9
3272 changed files with 66339 additions and 281594 deletions

View File

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

View File

@@ -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
View File

@@ -0,0 +1,5 @@
from sqlalchemy.orm import declarative_base
from models.engine import metadata
Base = declarative_base(metadata=metadata)

View File

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

View File

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

View File

@@ -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.
"""

View File

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

View File

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

View File

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

View File

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

View File

@@ -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()
)