diff --git a/.github/workflows/build-push.yml b/.github/workflows/build-push.yml index cc735ae67c..b933560a5e 100644 --- a/.github/workflows/build-push.yml +++ b/.github/workflows/build-push.yml @@ -6,6 +6,7 @@ on: - "main" - "deploy/dev" - "deploy/enterprise" + - "build/**" tags: - "*" diff --git a/api/.env.example b/api/.env.example index baa9c382c8..01fcad599e 100644 --- a/api/.env.example +++ b/api/.env.example @@ -451,6 +451,16 @@ APP_MAX_ACTIVE_REQUESTS=0 # Celery beat configuration CELERY_BEAT_SCHEDULER_TIME=1 +# Celery schedule tasks configuration +ENABLE_CLEAN_EMBEDDING_CACHE_TASK=false +ENABLE_CLEAN_UNUSED_DATASETS_TASK=false +ENABLE_CREATE_TIDB_SERVERLESS_TASK=false +ENABLE_UPDATE_TIDB_SERVERLESS_STATUS_TASK=false +ENABLE_CLEAN_MESSAGES=false +ENABLE_MAIL_CLEAN_DOCUMENT_NOTIFY_TASK=false +ENABLE_DATASETS_QUEUE_MONITOR=false +ENABLE_CHECK_UPGRADABLE_PLUGIN_TASK=true + # Position configuration POSITION_TOOL_PINS= POSITION_TOOL_INCLUDES= diff --git a/api/configs/feature/__init__.py b/api/configs/feature/__init__.py index df15b92c35..c2eaa89b6e 100644 --- a/api/configs/feature/__init__.py +++ b/api/configs/feature/__init__.py @@ -779,6 +779,41 @@ class CeleryBeatConfig(BaseSettings): ) +class CeleryScheduleTasksConfig(BaseSettings): + ENABLE_CLEAN_EMBEDDING_CACHE_TASK: bool = Field( + description="Enable clean embedding cache task", + default=False, + ) + ENABLE_CLEAN_UNUSED_DATASETS_TASK: bool = Field( + description="Enable clean unused datasets task", + default=False, + ) + ENABLE_CREATE_TIDB_SERVERLESS_TASK: bool = Field( + description="Enable create tidb service job task", + default=False, + ) + ENABLE_UPDATE_TIDB_SERVERLESS_STATUS_TASK: bool = Field( + description="Enable update tidb service job status task", + default=False, + ) + ENABLE_CLEAN_MESSAGES: bool = Field( + description="Enable clean messages task", + default=False, + ) + ENABLE_MAIL_CLEAN_DOCUMENT_NOTIFY_TASK: bool = Field( + description="Enable mail clean document notify task", + default=False, + ) + ENABLE_DATASETS_QUEUE_MONITOR: bool = Field( + description="Enable queue monitor task", + default=False, + ) + ENABLE_CHECK_UPGRADABLE_PLUGIN_TASK: bool = Field( + description="Enable check upgradable plugin task", + default=True, + ) + + class PositionConfig(BaseSettings): POSITION_PROVIDER_PINS: str = Field( description="Comma-separated list of pinned model providers", @@ -907,5 +942,6 @@ class FeatureConfig( # hosted services config HostedServiceConfig, CeleryBeatConfig, + CeleryScheduleTasksConfig, ): pass diff --git a/api/controllers/console/workspace/plugin.py b/api/controllers/console/workspace/plugin.py index 3b7c15688c..2027ca6826 100644 --- a/api/controllers/console/workspace/plugin.py +++ b/api/controllers/console/workspace/plugin.py @@ -533,7 +533,8 @@ class PluginFetchDynamicSelectOptionsApi(Resource): raise ValueError(e) return jsonable_encoder({"options": options}) - + + class PluginChangePreferencesApi(Resource): @setup_required @login_required @@ -597,29 +598,26 @@ class PluginFetchPreferencesApi(Resource): tenant_id = current_user.current_tenant_id permission = PluginPermissionService.get_permission(tenant_id) + permission_dict = { + "install_permission": TenantPluginPermission.InstallPermission.EVERYONE, + "debug_permission": TenantPluginPermission.DebugPermission.EVERYONE, + } - if not permission: - permission = { - "install_permission": TenantPluginPermission.InstallPermission.EVERYONE, - "debug_permission": TenantPluginPermission.DebugPermission.EVERYONE, - } - else: - permission = { - "install_permission": permission.install_permission, - "debug_permission": permission.debug_permission, - } + if permission: + permission_dict["install_permission"] = permission.install_permission + permission_dict["debug_permission"] = permission.debug_permission auto_upgrade = PluginAutoUpgradeService.get_strategy(tenant_id) - if not auto_upgrade: - auto_upgrade = { - "strategy_setting": TenantPluginAutoUpgradeStrategy.StrategySetting.FIX_ONLY, - "upgrade_time_of_day": 0, - "upgrade_mode": TenantPluginAutoUpgradeStrategy.UpgradeMode.EXCLUDE, - "exclude_plugins": [], - "include_plugins": [], - } - else: - auto_upgrade = { + auto_upgrade_dict = { + "strategy_setting": TenantPluginAutoUpgradeStrategy.StrategySetting.FIX_ONLY, + "upgrade_time_of_day": 0, + "upgrade_mode": TenantPluginAutoUpgradeStrategy.UpgradeMode.EXCLUDE, + "exclude_plugins": [], + "include_plugins": [], + } + + if auto_upgrade: + auto_upgrade_dict = { "strategy_setting": auto_upgrade.strategy_setting, "upgrade_time_of_day": auto_upgrade.upgrade_time_of_day, "upgrade_mode": auto_upgrade.upgrade_mode, @@ -627,7 +625,7 @@ class PluginFetchPreferencesApi(Resource): "include_plugins": auto_upgrade.include_plugins, } - return jsonable_encoder({"permission": permission, "auto_upgrade": auto_upgrade}) + return jsonable_encoder({"permission": permission_dict, "auto_upgrade": auto_upgrade_dict}) class PluginAutoUpgradeExcludePluginApi(Resource): diff --git a/api/core/helper/marketplace.py b/api/core/helper/marketplace.py index 65bf4fc1db..fe3078923d 100644 --- a/api/core/helper/marketplace.py +++ b/api/core/helper/marketplace.py @@ -25,9 +25,29 @@ def batch_fetch_plugin_manifests(plugin_ids: list[str]) -> Sequence[MarketplaceP url = str(marketplace_api_url / "api/v1/plugins/batch") response = requests.post(url, json={"plugin_ids": plugin_ids}) response.raise_for_status() + return [MarketplacePluginDeclaration(**plugin) for plugin in response.json()["data"]["plugins"]] +def batch_fetch_plugin_manifests_ignore_deserialization_error( + plugin_ids: list[str], +) -> Sequence[MarketplacePluginDeclaration]: + if len(plugin_ids) == 0: + return [] + + url = str(marketplace_api_url / "api/v1/plugins/batch") + response = requests.post(url, json={"plugin_ids": plugin_ids}) + response.raise_for_status() + result: list[MarketplacePluginDeclaration] = [] + for plugin in response.json()["data"]["plugins"]: + try: + result.append(MarketplacePluginDeclaration(**plugin)) + except Exception as e: + pass + + return result + + def record_install_plugin_event(plugin_unique_identifier: str): url = str(marketplace_api_url / "api/v1/stats/plugins/install_count") response = requests.post(url, json={"unique_identifier": plugin_unique_identifier}) diff --git a/api/core/rag/datasource/vdb/qdrant/qdrant_vector.py b/api/core/rag/datasource/vdb/qdrant/qdrant_vector.py index 8ce194c683..05fa73011a 100644 --- a/api/core/rag/datasource/vdb/qdrant/qdrant_vector.py +++ b/api/core/rag/datasource/vdb/qdrant/qdrant_vector.py @@ -47,6 +47,7 @@ class QdrantConfig(BaseModel): grpc_port: int = 6334 prefer_grpc: bool = False replication_factor: int = 1 + write_consistency_factor: int = 1 def to_qdrant_params(self): if self.endpoint and self.endpoint.startswith("path:"): @@ -127,6 +128,7 @@ class QdrantVector(BaseVector): hnsw_config=hnsw_config, timeout=int(self._client_config.timeout), replication_factor=self._client_config.replication_factor, + write_consistency_factor=self._client_config.write_consistency_factor, ) # create group_id payload index diff --git a/api/core/rag/datasource/vdb/vector_factory.py b/api/core/rag/datasource/vdb/vector_factory.py index 67a4a515b1..00080b0fae 100644 --- a/api/core/rag/datasource/vdb/vector_factory.py +++ b/api/core/rag/datasource/vdb/vector_factory.py @@ -1,3 +1,5 @@ +import logging +import time from abc import ABC, abstractmethod from typing import Any, Optional @@ -13,6 +15,8 @@ from extensions.ext_database import db from extensions.ext_redis import redis_client from models.dataset import Dataset, Whitelist +logger = logging.getLogger(__name__) + class AbstractVectorFactory(ABC): @abstractmethod @@ -173,8 +177,20 @@ class Vector: def create(self, texts: Optional[list] = None, **kwargs): if texts: - embeddings = self._embeddings.embed_documents([document.page_content for document in texts]) - self._vector_processor.create(texts=texts, embeddings=embeddings, **kwargs) + start = time.time() + logger.info(f"start embedding {len(texts)} texts {start}") + batch_size = 1000 + total_batches = len(texts) + batch_size - 1 + for i in range(0, len(texts), batch_size): + batch = texts[i : i + batch_size] + batch_start = time.time() + logger.info(f"Processing batch {i // batch_size + 1}/{total_batches} ({len(batch)} texts)") + batch_embeddings = self._embeddings.embed_documents([document.page_content for document in batch]) + logger.info( + f"Embedding batch {i // batch_size + 1}/{total_batches} took {time.time() - batch_start:.3f}s" + ) + self._vector_processor.create(texts=batch, embeddings=batch_embeddings, **kwargs) + logger.info(f"Embedding {len(texts)} texts took {time.time() - start:.3f}s") def add_texts(self, documents: list[Document], **kwargs): if kwargs.get("duplicate_check", False): diff --git a/api/core/workflow/callbacks/workflow_logging_callback.py b/api/core/workflow/callbacks/workflow_logging_callback.py index e6813a3997..12b5203ca3 100644 --- a/api/core/workflow/callbacks/workflow_logging_callback.py +++ b/api/core/workflow/callbacks/workflow_logging_callback.py @@ -232,14 +232,14 @@ class WorkflowLoggingCallback(WorkflowCallback): Publish loop started """ self.print_text("\n[LoopRunStartedEvent]", color="blue") - self.print_text(f"Loop Node ID: {event.loop_id}", color="blue") + self.print_text(f"Loop Node ID: {event.loop_node_id}", color="blue") def on_workflow_loop_next(self, event: LoopRunNextEvent) -> None: """ Publish loop next """ self.print_text("\n[LoopRunNextEvent]", color="blue") - self.print_text(f"Loop Node ID: {event.loop_id}", color="blue") + self.print_text(f"Loop Node ID: {event.loop_node_id}", color="blue") self.print_text(f"Loop Index: {event.index}", color="blue") def on_workflow_loop_completed(self, event: LoopRunSucceededEvent | LoopRunFailedEvent) -> None: @@ -250,7 +250,7 @@ class WorkflowLoggingCallback(WorkflowCallback): "\n[LoopRunSucceededEvent]" if isinstance(event, LoopRunSucceededEvent) else "\n[LoopRunFailedEvent]", color="blue", ) - self.print_text(f"Node ID: {event.loop_id}", color="blue") + self.print_text(f"Loop Node ID: {event.loop_node_id}", color="blue") def print_text(self, text: str, color: Optional[str] = None, end: str = "\n") -> None: """Print text with highlighting and no end characters.""" diff --git a/api/core/workflow/graph_engine/entities/graph.py b/api/core/workflow/graph_engine/entities/graph.py index 8e5b1e7142..362777a199 100644 --- a/api/core/workflow/graph_engine/entities/graph.py +++ b/api/core/workflow/graph_engine/entities/graph.py @@ -334,7 +334,7 @@ class Graph(BaseModel): parallel = GraphParallel( start_from_node_id=start_node_id, - parent_parallel_id=parent_parallel.id if parent_parallel else None, + parent_parallel_id=parent_parallel_id, parent_parallel_start_node_id=parent_parallel.start_from_node_id if parent_parallel else None, ) parallel_mapping[parallel.id] = parallel diff --git a/api/core/workflow/nodes/tool/tool_node.py b/api/core/workflow/nodes/tool/tool_node.py index 2d84ff0710..f5898dd605 100644 --- a/api/core/workflow/nodes/tool/tool_node.py +++ b/api/core/workflow/nodes/tool/tool_node.py @@ -285,7 +285,8 @@ class ToolNode(BaseNode[ToolNodeData]): for key, value in msg_metadata.items() if key in WorkflowNodeExecutionMetadataKey.__members__.values() } - json.append(message.message.json_object) + if message.message.json_object is not None: + json.append(message.message.json_object) elif message.type == ToolInvokeMessage.MessageType.LINK: assert isinstance(message.message, ToolInvokeMessage.TextMessage) stream_text = f"Link: {message.message.text}\n" @@ -369,31 +370,31 @@ class ToolNode(BaseNode[ToolNodeData]): agent_logs.append(agent_log) yield agent_log + # Add agent_logs to outputs['json'] to ensure frontend can access thinking process - json_output: dict[str, Any] = {} - if json: - if isinstance(json, list) and len(json) == 1: - # If json is a list with only one element, convert it to a dictionary - json_output = json[0] if isinstance(json[0], dict) else {"data": json[0]} - elif isinstance(json, list): - # If json is a list with multiple elements, create a dictionary containing all data - json_output = {"data": json} + json_output: list[dict[str, Any]] = [] + # Step 1: append each agent log as its own dict. if agent_logs: - # Add agent_logs to json output - json_output["agent_logs"] = [ - { - "id": log.id, - "parent_id": log.parent_id, - "error": log.error, - "status": log.status, - "data": log.data, - "label": log.label, - "metadata": log.metadata, - "node_id": log.node_id, - } - for log in agent_logs - ] + for log in agent_logs: + json_output.append( + { + "id": log.id, + "parent_id": log.parent_id, + "error": log.error, + "status": log.status, + "data": log.data, + "label": log.label, + "metadata": log.metadata, + "node_id": log.node_id, + } + ) + # Step 2: normalize JSON into {"data": [...]}.change json to list[dict] + if json: + json_output.extend(json) + else: + json_output.append({"data": []}) + yield RunCompletedEvent( run_result=NodeRunResult( status=WorkflowNodeExecutionStatus.SUCCEEDED, diff --git a/api/extensions/ext_celery.py b/api/extensions/ext_celery.py index be89705858..2c2846ba26 100644 --- a/api/extensions/ext_celery.py +++ b/api/extensions/ext_celery.py @@ -64,55 +64,62 @@ def init_app(app: DifyApp) -> Celery: celery_app.set_default() app.extensions["celery"] = celery_app - imports = [ - "schedule.clean_embedding_cache_task", - "schedule.clean_unused_datasets_task", - "schedule.create_tidb_serverless_task", - "schedule.update_tidb_serverless_status_task", - "schedule.clean_messages", - "schedule.mail_clean_document_notify_task", - "schedule.queue_monitor_task", - "schedule.check_upgradable_plugin_task", - ] + imports = [] day = dify_config.CELERY_BEAT_SCHEDULER_TIME - beat_schedule = { - "clean_embedding_cache_task": { + + # if you add a new task, please add the switch to CeleryScheduleTasksConfig + beat_schedule = {} + if dify_config.ENABLE_CLEAN_EMBEDDING_CACHE_TASK: + imports.append("schedule.clean_embedding_cache_task") + beat_schedule["clean_embedding_cache_task"] = { "task": "schedule.clean_embedding_cache_task.clean_embedding_cache_task", "schedule": timedelta(days=day), - }, - "clean_unused_datasets_task": { + } + if dify_config.ENABLE_CLEAN_UNUSED_DATASETS_TASK: + imports.append("schedule.clean_unused_datasets_task") + beat_schedule["clean_unused_datasets_task"] = { "task": "schedule.clean_unused_datasets_task.clean_unused_datasets_task", "schedule": timedelta(days=day), - }, - "create_tidb_serverless_task": { + } + if dify_config.ENABLE_CREATE_TIDB_SERVERLESS_TASK: + imports.append("schedule.create_tidb_serverless_task") + beat_schedule["create_tidb_serverless_task"] = { "task": "schedule.create_tidb_serverless_task.create_tidb_serverless_task", "schedule": crontab(minute="0", hour="*"), - }, - "update_tidb_serverless_status_task": { + } + if dify_config.ENABLE_UPDATE_TIDB_SERVERLESS_STATUS_TASK: + imports.append("schedule.update_tidb_serverless_status_task") + beat_schedule["update_tidb_serverless_status_task"] = { "task": "schedule.update_tidb_serverless_status_task.update_tidb_serverless_status_task", "schedule": timedelta(minutes=10), - }, - "clean_messages": { + } + if dify_config.ENABLE_CLEAN_MESSAGES: + imports.append("schedule.clean_messages") + beat_schedule["clean_messages"] = { "task": "schedule.clean_messages.clean_messages", "schedule": timedelta(days=day), - }, - # every Monday - "mail_clean_document_notify_task": { + } + if dify_config.ENABLE_MAIL_CLEAN_DOCUMENT_NOTIFY_TASK: + imports.append("schedule.mail_clean_document_notify_task") + beat_schedule["mail_clean_document_notify_task"] = { "task": "schedule.mail_clean_document_notify_task.mail_clean_document_notify_task", "schedule": crontab(minute="0", hour="10", day_of_week="1"), - }, - "datasets-queue-monitor": { + } + if dify_config.ENABLE_DATASETS_QUEUE_MONITOR: + imports.append("schedule.queue_monitor_task") + beat_schedule["datasets-queue-monitor"] = { "task": "schedule.queue_monitor_task.queue_monitor_task", "schedule": timedelta( minutes=dify_config.QUEUE_MONITOR_INTERVAL if dify_config.QUEUE_MONITOR_INTERVAL else 30 ), - }, - # every 15 minutes - "check_upgradable_plugin_task": { + } + if dify_config.ENABLE_CHECK_UPGRADABLE_PLUGIN_TASK: + imports.append("schedule.check_upgradable_plugin_task") + beat_schedule["check_upgradable_plugin_task"] = { "task": "schedule.check_upgradable_plugin_task.check_upgradable_plugin_task", "schedule": crontab(minute="*/15"), - }, - } + } + celery_app.conf.update(beat_schedule=beat_schedule, imports=imports) return celery_app diff --git a/api/extensions/ext_redis.py b/api/extensions/ext_redis.py index c283b1b7ca..be2f6115f7 100644 --- a/api/extensions/ext_redis.py +++ b/api/extensions/ext_redis.py @@ -1,6 +1,10 @@ +import functools +import logging +from collections.abc import Callable from typing import Any, Union import redis +from redis import RedisError from redis.cache import CacheConfig from redis.cluster import ClusterNode, RedisCluster from redis.connection import Connection, SSLConnection @@ -9,6 +13,8 @@ from redis.sentinel import Sentinel from configs import dify_config from dify_app import DifyApp +logger = logging.getLogger(__name__) + class RedisClientWrapper: """ @@ -115,3 +121,25 @@ def init_app(app: DifyApp): redis_client.initialize(redis.Redis(connection_pool=pool)) app.extensions["redis"] = redis_client + + +def redis_fallback(default_return: Any = None): + """ + decorator to handle Redis operation exceptions and return a default value when Redis is unavailable. + + Args: + default_return: The value to return when a Redis operation fails. Defaults to None. + """ + + def decorator(func: Callable): + @functools.wraps(func) + def wrapper(*args, **kwargs): + try: + return func(*args, **kwargs) + except RedisError as e: + logger.warning(f"Redis operation failed in {func.__name__}: {str(e)}", exc_info=True) + return default_return + + return wrapper + + return decorator diff --git a/api/migrations/versions/2025_05_15_1635-16081485540c_.py b/api/migrations/versions/2025_05_15_1635-16081485540c_.py new file mode 100644 index 0000000000..70ed771391 --- /dev/null +++ b/api/migrations/versions/2025_05_15_1635-16081485540c_.py @@ -0,0 +1,41 @@ +"""empty message + +Revision ID: 16081485540c +Revises: d28f2004b072 +Create Date: 2025-05-15 16:35:39.113777 + +""" +from alembic import op +import models as models +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '16081485540c' +down_revision = '58eb7bdb93fe' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('tenant_plugin_auto_upgrade_strategies', + sa.Column('id', models.types.StringUUID(), server_default=sa.text('uuid_generate_v4()'), nullable=False), + sa.Column('tenant_id', models.types.StringUUID(), nullable=False), + sa.Column('strategy_setting', sa.String(length=16), server_default='fix_only', nullable=False), + sa.Column('upgrade_time_of_day', sa.Integer(), nullable=False), + sa.Column('upgrade_mode', sa.String(length=16), server_default='exclude', nullable=False), + sa.Column('exclude_plugins', sa.ARRAY(sa.String(length=255)), nullable=False), + sa.Column('include_plugins', sa.ARRAY(sa.String(length=255)), nullable=False), + sa.Column('created_at', sa.DateTime(), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=False), + sa.Column('updated_at', sa.DateTime(), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=False), + sa.PrimaryKeyConstraint('id', name='tenant_plugin_auto_upgrade_strategy_pkey'), + sa.UniqueConstraint('tenant_id', name='unique_tenant_plugin_auto_upgrade_strategy') + ) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_table('tenant_plugin_auto_upgrade_strategies') + # ### end Alembic commands ### diff --git a/api/schedule/check_upgradable_plugin_task.py b/api/schedule/check_upgradable_plugin_task.py index b709689d27..c1d6018827 100644 --- a/api/schedule/check_upgradable_plugin_task.py +++ b/api/schedule/check_upgradable_plugin_task.py @@ -1,29 +1,23 @@ import time -import traceback import click import app -from core.helper import marketplace -from core.plugin.entities.plugin import PluginInstallationSource -from core.plugin.impl.plugin import PluginInstaller from extensions.ext_database import db from models.account import TenantPluginAutoUpgradeStrategy +from tasks.process_tenant_plugin_autoupgrade_check_task import process_tenant_plugin_autoupgrade_check_task AUTO_UPGRADE_MINIMAL_CHECKING_INTERVAL = 15 * 60 # 15 minutes -RETRY_TIMES_OF_ONE_PLUGIN_IN_ONE_TENANT = 3 - @app.celery.task(queue="plugin") def check_upgradable_plugin_task(): click.echo(click.style("Start check upgradable plugin.", fg="green")) start_at = time.perf_counter() - now_seconds_of_day = time.time() % 86400 # we assume the tz is UTC + now_seconds_of_day = time.time() % 86400 - 30 # we assume the tz is UTC click.echo(click.style("Now seconds of day: {}".format(now_seconds_of_day), fg="green")) - # get strategies that set to be performed in the next AUTO_UPGRADE_MINIMAL_CHECKING_INTERVAL strategies = ( db.session.query(TenantPluginAutoUpgradeStrategy) .filter( @@ -36,113 +30,15 @@ def check_upgradable_plugin_task(): .all() ) - manager = PluginInstaller() - for strategy in strategies: - try: - tenant_id = strategy.tenant_id - strategy_setting = strategy.strategy_setting - upgrade_mode = strategy.upgrade_mode - exclude_plugins = strategy.exclude_plugins - include_plugins = strategy.include_plugins - - if strategy_setting == TenantPluginAutoUpgradeStrategy.StrategySetting.DISABLED: - continue - - # get plugins that need to be checked - plugin_ids: list[tuple[str, str, str]] = [] # plugin_id, version, unique_identifier - - if upgrade_mode == TenantPluginAutoUpgradeStrategy.UpgradeMode.PARTIAL and include_plugins: - all_plugins = manager.list_plugins(tenant_id) - - for plugin in all_plugins: - if plugin.source == PluginInstallationSource.Marketplace and plugin.plugin_id in include_plugins: - plugin_ids.append((plugin.plugin_id, plugin.version, plugin.plugin_unique_identifier)) - - elif upgrade_mode == TenantPluginAutoUpgradeStrategy.UpgradeMode.EXCLUDE: - # get all plugins and remove the exclude plugins - all_plugins = manager.list_plugins(tenant_id) - plugin_ids = [ - (plugin.plugin_id, plugin.version, plugin.plugin_unique_identifier) - for plugin in all_plugins - if plugin.source == PluginInstallationSource.Marketplace and plugin.plugin_id not in exclude_plugins - ] - elif upgrade_mode == TenantPluginAutoUpgradeStrategy.UpgradeMode.ALL: - all_plugins = manager.list_plugins(tenant_id) - plugin_ids = [ - (plugin.plugin_id, plugin.version, plugin.plugin_unique_identifier) - for plugin in all_plugins - if plugin.source == PluginInstallationSource.Marketplace - ] - - if not plugin_ids: - continue - - plugin_ids_plain_list = [plugin_id for plugin_id, _, _ in plugin_ids] - - click.echo(click.style("Fetching manifests for plugins: {}".format(plugin_ids_plain_list), fg="green")) - - # fetch latest versions from marketplace - manifests = marketplace.batch_fetch_plugin_manifests(plugin_ids_plain_list) - - for manifest in manifests: - for plugin_id, version, original_unique_identifier in plugin_ids: - if manifest.plugin_id != plugin_id: - continue - - try: - current_version = version - latest_version = manifest.latest_version - - # @yeuoly review here - def fix_only_checker(latest_version, current_version): - latest_version_tuple = tuple(int(val) for val in latest_version.split(".")) - current_version_tuple = tuple(int(val) for val in current_version.split(".")) - - if ( - latest_version_tuple[0] == current_version_tuple[0] - and latest_version_tuple[1] == current_version_tuple[1] - ): - return latest_version_tuple[2] != current_version_tuple[2] - return False - - version_checker = { - TenantPluginAutoUpgradeStrategy.StrategySetting.LATEST: lambda latest_version, - current_version: latest_version != current_version, - TenantPluginAutoUpgradeStrategy.StrategySetting.FIX_ONLY: fix_only_checker, - } - - if version_checker[strategy_setting](latest_version, current_version): - # execute upgrade - new_unique_identifier = manifest.latest_package_identifier - - marketplace.record_install_plugin_event(new_unique_identifier) - click.echo( - click.style( - "Upgrade plugin: {} -> {}".format( - original_unique_identifier, new_unique_identifier - ), - fg="green", - ) - ) - task_start_resp = manager.upgrade_plugin( - tenant_id, - original_unique_identifier, - new_unique_identifier, - PluginInstallationSource.Marketplace, - { - "plugin_unique_identifier": new_unique_identifier, - }, - ) - except Exception as e: - click.echo(click.style("Error when upgrading plugin: {}".format(e), fg="red")) - traceback.print_exc() - break - - except Exception as e: - click.echo(click.style("Error when checking upgradable plugin: {}".format(e), fg="red")) - traceback.print_exc() - continue + process_tenant_plugin_autoupgrade_check_task.delay( + strategy.tenant_id, + strategy.strategy_setting, + strategy.upgrade_time_of_day, + strategy.upgrade_mode, + strategy.exclude_plugins, + strategy.include_plugins, + ) end_at = time.perf_counter() click.echo( diff --git a/api/services/account_service.py b/api/services/account_service.py index 3fdbda48a6..d9a9c4f280 100644 --- a/api/services/account_service.py +++ b/api/services/account_service.py @@ -16,7 +16,7 @@ from configs import dify_config from constants.languages import language_timezone_mapping, languages from events.tenant_event import tenant_was_created from extensions.ext_database import db -from extensions.ext_redis import redis_client +from extensions.ext_redis import redis_client, redis_fallback from libs.helper import RateLimiter, TokenManager from libs.passport import PassportService from libs.password import compare_password, hash_password, valid_password @@ -28,6 +28,7 @@ from models.account import ( Tenant, TenantAccountJoin, TenantAccountRole, + TenantPluginAutoUpgradeStrategy, TenantStatus, ) from models.model import DifySetup @@ -495,6 +496,7 @@ class AccountService: return account @staticmethod + @redis_fallback(default_return=None) def add_login_error_rate_limit(email: str) -> None: key = f"login_error_rate_limit:{email}" count = redis_client.get(key) @@ -504,6 +506,7 @@ class AccountService: redis_client.setex(key, dify_config.LOGIN_LOCKOUT_DURATION, count) @staticmethod + @redis_fallback(default_return=False) def is_login_error_rate_limit(email: str) -> bool: key = f"login_error_rate_limit:{email}" count = redis_client.get(key) @@ -516,11 +519,13 @@ class AccountService: return False @staticmethod + @redis_fallback(default_return=None) def reset_login_error_rate_limit(email: str): key = f"login_error_rate_limit:{email}" redis_client.delete(key) @staticmethod + @redis_fallback(default_return=None) def add_forgot_password_error_rate_limit(email: str) -> None: key = f"forgot_password_error_rate_limit:{email}" count = redis_client.get(key) @@ -530,6 +535,7 @@ class AccountService: redis_client.setex(key, dify_config.FORGOT_PASSWORD_LOCKOUT_DURATION, count) @staticmethod + @redis_fallback(default_return=False) def is_forgot_password_error_rate_limit(email: str) -> bool: key = f"forgot_password_error_rate_limit:{email}" count = redis_client.get(key) @@ -542,11 +548,13 @@ class AccountService: return False @staticmethod + @redis_fallback(default_return=None) def reset_forgot_password_error_rate_limit(email: str): key = f"forgot_password_error_rate_limit:{email}" redis_client.delete(key) @staticmethod + @redis_fallback(default_return=False) def is_email_send_ip_limit(ip_address: str): minute_key = f"email_send_ip_limit_minute:{ip_address}" freeze_key = f"email_send_ip_limit_freeze:{ip_address}" @@ -604,6 +612,17 @@ class TenantService: db.session.add(tenant) db.session.commit() + plugin_upgrade_strategy = TenantPluginAutoUpgradeStrategy( + tenant_id=tenant.id, + strategy_setting=TenantPluginAutoUpgradeStrategy.StrategySetting.FIX_ONLY, + upgrade_time_of_day=0, + upgrade_mode=TenantPluginAutoUpgradeStrategy.UpgradeMode.EXCLUDE, + exclude_plugins=[], + include_plugins=[], + ) + db.session.add(plugin_upgrade_strategy) + db.session.commit() + tenant.encrypt_public_key = generate_key_pair(tenant.id) db.session.commit() return tenant diff --git a/api/services/plugin/plugin_auto_upgrade_service.py b/api/services/plugin/plugin_auto_upgrade_service.py index d05292a4bc..3774050445 100644 --- a/api/services/plugin/plugin_auto_upgrade_service.py +++ b/api/services/plugin/plugin_auto_upgrade_service.py @@ -22,7 +22,7 @@ class PluginAutoUpgradeService: upgrade_mode: TenantPluginAutoUpgradeStrategy.UpgradeMode, exclude_plugins: list[str], include_plugins: list[str], - ) -> None: + ) -> bool: with Session(db.engine) as session: exist_strategy = ( session.query(TenantPluginAutoUpgradeStrategy) diff --git a/api/tasks/clean_document_task.py b/api/tasks/clean_document_task.py index 5824121e8f..c72a3319c1 100644 --- a/api/tasks/clean_document_task.py +++ b/api/tasks/clean_document_task.py @@ -72,6 +72,7 @@ def clean_document_task(document_id: str, dataset_id: str, doc_form: str, file_i DatasetMetadataBinding.dataset_id == dataset_id, DatasetMetadataBinding.document_id == document_id, ).delete() + db.session.commit() end_at = time.perf_counter() logging.info( diff --git a/api/tasks/process_tenant_plugin_autoupgrade_check_task.py b/api/tasks/process_tenant_plugin_autoupgrade_check_task.py new file mode 100644 index 0000000000..42484814fe --- /dev/null +++ b/api/tasks/process_tenant_plugin_autoupgrade_check_task.py @@ -0,0 +1,166 @@ +import traceback +import typing + +import click +from celery import shared_task # type: ignore + +from core.helper import marketplace +from core.helper.marketplace import MarketplacePluginDeclaration +from core.plugin.entities.plugin import PluginInstallationSource +from core.plugin.impl.plugin import PluginInstaller +from models.account import TenantPluginAutoUpgradeStrategy + +RETRY_TIMES_OF_ONE_PLUGIN_IN_ONE_TENANT = 3 + + +cached_plugin_manifests: dict[str, typing.Union[MarketplacePluginDeclaration, None]] = {} + + +def marketplace_batch_fetch_plugin_manifests( + plugin_ids_plain_list: list[str], +) -> list[MarketplacePluginDeclaration]: + global cached_plugin_manifests + # return marketplace.batch_fetch_plugin_manifests(plugin_ids_plain_list) + not_included_plugin_ids = [ + plugin_id for plugin_id in plugin_ids_plain_list if plugin_id not in cached_plugin_manifests + ] + if not_included_plugin_ids: + manifests = marketplace.batch_fetch_plugin_manifests_ignore_deserialization_error(not_included_plugin_ids) + for manifest in manifests: + cached_plugin_manifests[manifest.plugin_id] = manifest + + if ( + len(manifests) == 0 + ): # this indicates that the plugin not found in marketplace, should set None in cache to prevent future check + for plugin_id in not_included_plugin_ids: + cached_plugin_manifests[plugin_id] = None + + result: list[MarketplacePluginDeclaration] = [] + for plugin_id in plugin_ids_plain_list: + final_manifest = cached_plugin_manifests.get(plugin_id) + if final_manifest is not None: + result.append(final_manifest) + + return result + + +@shared_task(queue="plugin") +def process_tenant_plugin_autoupgrade_check_task( + tenant_id: str, + strategy_setting: TenantPluginAutoUpgradeStrategy.StrategySetting, + upgrade_time_of_day: int, + upgrade_mode: TenantPluginAutoUpgradeStrategy.UpgradeMode, + exclude_plugins: list[str], + include_plugins: list[str], +): + try: + manager = PluginInstaller() + + click.echo( + click.style( + "Checking upgradable plugin for tenant: {}".format(tenant_id), + fg="green", + ) + ) + + if strategy_setting == TenantPluginAutoUpgradeStrategy.StrategySetting.DISABLED: + return + + # 获取需要检查的插件 + plugin_ids: list[tuple[str, str, str]] = [] # plugin_id, version, unique_identifier + click.echo(click.style("Upgrade mode: {}".format(upgrade_mode), fg="green")) + + if upgrade_mode == TenantPluginAutoUpgradeStrategy.UpgradeMode.PARTIAL and include_plugins: + all_plugins = manager.list_plugins(tenant_id) + + for plugin in all_plugins: + if plugin.source == PluginInstallationSource.Marketplace and plugin.plugin_id in include_plugins: + plugin_ids.append( + ( + plugin.plugin_id, + plugin.version, + plugin.plugin_unique_identifier, + ) + ) + + elif upgrade_mode == TenantPluginAutoUpgradeStrategy.UpgradeMode.EXCLUDE: + # 获取所有插件并移除exclude的 + all_plugins = manager.list_plugins(tenant_id) + plugin_ids = [ + (plugin.plugin_id, plugin.version, plugin.plugin_unique_identifier) + for plugin in all_plugins + if plugin.source == PluginInstallationSource.Marketplace and plugin.plugin_id not in exclude_plugins + ] + elif upgrade_mode == TenantPluginAutoUpgradeStrategy.UpgradeMode.ALL: + all_plugins = manager.list_plugins(tenant_id) + plugin_ids = [ + (plugin.plugin_id, plugin.version, plugin.plugin_unique_identifier) + for plugin in all_plugins + if plugin.source == PluginInstallationSource.Marketplace + ] + + if not plugin_ids: + return + + plugin_ids_plain_list = [plugin_id for plugin_id, _, _ in plugin_ids] + + manifests = marketplace_batch_fetch_plugin_manifests(plugin_ids_plain_list) + + if not manifests: + return + + for manifest in manifests: + for plugin_id, version, original_unique_identifier in plugin_ids: + if manifest.plugin_id != plugin_id: + continue + + try: + current_version = version + latest_version = manifest.latest_version + + def fix_only_checker(latest_version, current_version): + latest_version_tuple = tuple(int(val) for val in latest_version.split(".")) + current_version_tuple = tuple(int(val) for val in current_version.split(".")) + + if ( + latest_version_tuple[0] == current_version_tuple[0] + and latest_version_tuple[1] == current_version_tuple[1] + ): + return latest_version_tuple[2] != current_version_tuple[2] + return False + + version_checker = { + TenantPluginAutoUpgradeStrategy.StrategySetting.LATEST: lambda latest_version, + current_version: latest_version != current_version, + TenantPluginAutoUpgradeStrategy.StrategySetting.FIX_ONLY: fix_only_checker, + } + + if version_checker[strategy_setting](latest_version, current_version): + # 执行升级 + new_unique_identifier = manifest.latest_package_identifier + + marketplace.record_install_plugin_event(new_unique_identifier) + click.echo( + click.style( + "Upgrade plugin: {} -> {}".format(original_unique_identifier, new_unique_identifier), + fg="green", + ) + ) + task_start_resp = manager.upgrade_plugin( + tenant_id, + original_unique_identifier, + new_unique_identifier, + PluginInstallationSource.Marketplace, + { + "plugin_unique_identifier": new_unique_identifier, + }, + ) + except Exception as e: + click.echo(click.style("Error when upgrading plugin: {}".format(e), fg="red")) + traceback.print_exc() + break + + except Exception as e: + click.echo(click.style("Error when checking upgradable plugin: {}".format(e), fg="red")) + traceback.print_exc() + return diff --git a/api/tests/integration_tests/vdb/couchbase/test_couchbase.py b/api/tests/integration_tests/vdb/couchbase/test_couchbase.py index d76c34ba0e..eef1ee4e75 100644 --- a/api/tests/integration_tests/vdb/couchbase/test_couchbase.py +++ b/api/tests/integration_tests/vdb/couchbase/test_couchbase.py @@ -4,7 +4,6 @@ import time from core.rag.datasource.vdb.couchbase.couchbase_vector import CouchbaseConfig, CouchbaseVector from tests.integration_tests.vdb.test_vector_store import ( AbstractVectorTest, - get_example_text, setup_mock_redis, ) diff --git a/api/tests/integration_tests/vdb/matrixone/test_matrixone.py b/api/tests/integration_tests/vdb/matrixone/test_matrixone.py index c8b19ef3ad..c4056db63e 100644 --- a/api/tests/integration_tests/vdb/matrixone/test_matrixone.py +++ b/api/tests/integration_tests/vdb/matrixone/test_matrixone.py @@ -1,7 +1,6 @@ from core.rag.datasource.vdb.matrixone.matrixone_vector import MatrixoneConfig, MatrixoneVector from tests.integration_tests.vdb.test_vector_store import ( AbstractVectorTest, - get_example_text, setup_mock_redis, ) diff --git a/api/tests/integration_tests/vdb/opengauss/test_opengauss.py b/api/tests/integration_tests/vdb/opengauss/test_opengauss.py index f2013848bf..2a1129493c 100644 --- a/api/tests/integration_tests/vdb/opengauss/test_opengauss.py +++ b/api/tests/integration_tests/vdb/opengauss/test_opengauss.py @@ -5,7 +5,6 @@ import psycopg2 # type: ignore from core.rag.datasource.vdb.opengauss.opengauss import OpenGauss, OpenGaussConfig from tests.integration_tests.vdb.test_vector_store import ( AbstractVectorTest, - get_example_text, setup_mock_redis, ) diff --git a/api/tests/integration_tests/vdb/pyvastbase/test_vastbase_vector.py b/api/tests/integration_tests/vdb/pyvastbase/test_vastbase_vector.py index 3d7873442b..02931fef5a 100644 --- a/api/tests/integration_tests/vdb/pyvastbase/test_vastbase_vector.py +++ b/api/tests/integration_tests/vdb/pyvastbase/test_vastbase_vector.py @@ -1,7 +1,6 @@ from core.rag.datasource.vdb.pyvastbase.vastbase_vector import VastbaseVector, VastbaseVectorConfig from tests.integration_tests.vdb.test_vector_store import ( AbstractVectorTest, - get_example_text, setup_mock_redis, ) diff --git a/api/tests/integration_tests/workflow/nodes/test_llm.py b/api/tests/integration_tests/workflow/nodes/test_llm.py index 389d1071f3..638323f850 100644 --- a/api/tests/integration_tests/workflow/nodes/test_llm.py +++ b/api/tests/integration_tests/workflow/nodes/test_llm.py @@ -1,5 +1,4 @@ import json -import os import time import uuid from collections.abc import Generator @@ -113,8 +112,6 @@ def test_execute_llm(flask_req_ctx): }, ) - credentials = {"openai_api_key": os.environ.get("OPENAI_API_KEY")} - # Create a proper LLM result with real entities mock_usage = LLMUsage( prompt_tokens=30, diff --git a/api/tests/unit_tests/core/helper/test_encrypter.py b/api/tests/unit_tests/core/helper/test_encrypter.py new file mode 100644 index 0000000000..61cf8f255d --- /dev/null +++ b/api/tests/unit_tests/core/helper/test_encrypter.py @@ -0,0 +1,280 @@ +import base64 +import binascii +from unittest.mock import MagicMock, patch + +import pytest + +from core.helper.encrypter import ( + batch_decrypt_token, + decrypt_token, + encrypt_token, + get_decrypt_decoding, + obfuscated_token, +) +from libs.rsa import PrivkeyNotFoundError + + +class TestObfuscatedToken: + @pytest.mark.parametrize( + ("token", "expected"), + [ + ("", ""), # Empty token + ("1234567", "*" * 20), # Short token (<8 chars) + ("12345678", "*" * 20), # Boundary case (8 chars) + ("123456789abcdef", "123456" + "*" * 12 + "ef"), # Long token + ("abc!@#$%^&*()def", "abc!@#" + "*" * 12 + "ef"), # Special chars + ], + ) + def test_obfuscation_logic(self, token, expected): + """Test core obfuscation logic for various token lengths""" + assert obfuscated_token(token) == expected + + def test_sensitive_data_protection(self): + """Ensure obfuscation never reveals full sensitive data""" + token = "api_key_secret_12345" + obfuscated = obfuscated_token(token) + assert token not in obfuscated + assert "*" * 12 in obfuscated + + +class TestEncryptToken: + @patch("models.engine.db.session.query") + @patch("libs.rsa.encrypt") + def test_successful_encryption(self, mock_encrypt, mock_query): + """Test successful token encryption""" + mock_tenant = MagicMock() + mock_tenant.encrypt_public_key = "mock_public_key" + mock_query.return_value.filter.return_value.first.return_value = mock_tenant + mock_encrypt.return_value = b"encrypted_data" + + result = encrypt_token("tenant-123", "test_token") + + assert result == base64.b64encode(b"encrypted_data").decode() + mock_encrypt.assert_called_with("test_token", "mock_public_key") + + @patch("models.engine.db.session.query") + def test_tenant_not_found(self, mock_query): + """Test error when tenant doesn't exist""" + mock_query.return_value.filter.return_value.first.return_value = None + + with pytest.raises(ValueError) as exc_info: + encrypt_token("invalid-tenant", "test_token") + + assert "Tenant with id invalid-tenant not found" in str(exc_info.value) + + +class TestDecryptToken: + @patch("libs.rsa.decrypt") + def test_successful_decryption(self, mock_decrypt): + """Test successful token decryption""" + mock_decrypt.return_value = "decrypted_token" + encrypted_data = base64.b64encode(b"encrypted_data").decode() + + result = decrypt_token("tenant-123", encrypted_data) + + assert result == "decrypted_token" + mock_decrypt.assert_called_once_with(b"encrypted_data", "tenant-123") + + def test_invalid_base64(self): + """Test handling of invalid base64 input""" + with pytest.raises(binascii.Error): + decrypt_token("tenant-123", "invalid_base64!!!") + + +class TestBatchDecryptToken: + @patch("libs.rsa.get_decrypt_decoding") + @patch("libs.rsa.decrypt_token_with_decoding") + def test_batch_decryption(self, mock_decrypt_with_decoding, mock_get_decoding): + """Test batch decryption functionality""" + mock_rsa_key = MagicMock() + mock_cipher_rsa = MagicMock() + mock_get_decoding.return_value = (mock_rsa_key, mock_cipher_rsa) + + # Test multiple tokens + mock_decrypt_with_decoding.side_effect = ["token1", "token2", "token3"] + tokens = [ + base64.b64encode(b"encrypted1").decode(), + base64.b64encode(b"encrypted2").decode(), + base64.b64encode(b"encrypted3").decode(), + ] + result = batch_decrypt_token("tenant-123", tokens) + + assert result == ["token1", "token2", "token3"] + # Key should only be loaded once + mock_get_decoding.assert_called_once_with("tenant-123") + + +class TestGetDecryptDecoding: + @patch("extensions.ext_redis.redis_client.get") + @patch("extensions.ext_storage.storage.load") + def test_private_key_not_found(self, mock_storage_load, mock_redis_get): + """Test error when private key file doesn't exist""" + mock_redis_get.return_value = None + mock_storage_load.side_effect = FileNotFoundError() + + with pytest.raises(PrivkeyNotFoundError) as exc_info: + get_decrypt_decoding("tenant-123") + + assert "Private key not found, tenant_id: tenant-123" in str(exc_info.value) + + +class TestEncryptDecryptIntegration: + @patch("models.engine.db.session.query") + @patch("libs.rsa.encrypt") + @patch("libs.rsa.decrypt") + def test_should_encrypt_and_decrypt_consistently(self, mock_decrypt, mock_encrypt, mock_query): + """Test that encryption and decryption are consistent""" + # Setup mock tenant + mock_tenant = MagicMock() + mock_tenant.encrypt_public_key = "mock_public_key" + mock_query.return_value.filter.return_value.first.return_value = mock_tenant + + # Setup mock encryption/decryption + original_token = "test_token_123" + mock_encrypt.return_value = b"encrypted_data" + mock_decrypt.return_value = original_token + + # Test encryption + encrypted = encrypt_token("tenant-123", original_token) + + # Test decryption + decrypted = decrypt_token("tenant-123", encrypted) + + assert decrypted == original_token + + +class TestSecurity: + """Critical security tests for encryption system""" + + @patch("models.engine.db.session.query") + @patch("libs.rsa.encrypt") + def test_cross_tenant_isolation(self, mock_encrypt, mock_query): + """Ensure tokens encrypted for one tenant cannot be used by another""" + # Setup mock tenant + mock_tenant = MagicMock() + mock_tenant.encrypt_public_key = "tenant1_public_key" + mock_query.return_value.filter.return_value.first.return_value = mock_tenant + mock_encrypt.return_value = b"encrypted_for_tenant1" + + # Encrypt token for tenant1 + encrypted = encrypt_token("tenant-123", "sensitive_data") + + # Attempt to decrypt with different tenant should fail + with patch("libs.rsa.decrypt") as mock_decrypt: + mock_decrypt.side_effect = Exception("Invalid tenant key") + + with pytest.raises(Exception, match="Invalid tenant key"): + decrypt_token("different-tenant", encrypted) + + @patch("libs.rsa.decrypt") + def test_tampered_ciphertext_rejection(self, mock_decrypt): + """Detect and reject tampered ciphertext""" + valid_encrypted = base64.b64encode(b"valid_data").decode() + + # Tamper with ciphertext + tampered_bytes = bytearray(base64.b64decode(valid_encrypted)) + tampered_bytes[0] ^= 0xFF + tampered = base64.b64encode(bytes(tampered_bytes)).decode() + + mock_decrypt.side_effect = Exception("Decryption error") + + with pytest.raises(Exception, match="Decryption error"): + decrypt_token("tenant-123", tampered) + + @patch("models.engine.db.session.query") + @patch("libs.rsa.encrypt") + def test_encryption_randomness(self, mock_encrypt, mock_query): + """Ensure same plaintext produces different ciphertext""" + mock_tenant = MagicMock(encrypt_public_key="key") + mock_query.return_value.filter.return_value.first.return_value = mock_tenant + + # Different outputs for same input + mock_encrypt.side_effect = [b"enc1", b"enc2", b"enc3"] + + results = [encrypt_token("tenant-123", "token") for _ in range(3)] + + # All results should be different + assert len(set(results)) == 3 + + +class TestEdgeCases: + """Additional security-focused edge case tests""" + + def test_should_handle_empty_string_in_obfuscation(self): + """Test handling of empty string in obfuscation""" + # Test empty string (which is a valid str type) + assert obfuscated_token("") == "" + + @patch("models.engine.db.session.query") + @patch("libs.rsa.encrypt") + def test_should_handle_empty_token_encryption(self, mock_encrypt, mock_query): + """Test encryption of empty token""" + mock_tenant = MagicMock() + mock_tenant.encrypt_public_key = "mock_public_key" + mock_query.return_value.filter.return_value.first.return_value = mock_tenant + mock_encrypt.return_value = b"encrypted_empty" + + result = encrypt_token("tenant-123", "") + + assert result == base64.b64encode(b"encrypted_empty").decode() + mock_encrypt.assert_called_with("", "mock_public_key") + + @patch("models.engine.db.session.query") + @patch("libs.rsa.encrypt") + def test_should_handle_special_characters_in_token(self, mock_encrypt, mock_query): + """Test tokens containing special/unicode characters""" + mock_tenant = MagicMock() + mock_tenant.encrypt_public_key = "mock_public_key" + mock_query.return_value.filter.return_value.first.return_value = mock_tenant + mock_encrypt.return_value = b"encrypted_special" + + # Test various special characters + special_tokens = [ + "token\x00with\x00null", # Null bytes + "token_with_emoji_😀🎉", # Unicode emoji + "token\nwith\nnewlines", # Newlines + "token\twith\ttabs", # Tabs + "token_with_中文字符", # Chinese characters + ] + + for token in special_tokens: + result = encrypt_token("tenant-123", token) + assert result == base64.b64encode(b"encrypted_special").decode() + mock_encrypt.assert_called_with(token, "mock_public_key") + + @patch("models.engine.db.session.query") + @patch("libs.rsa.encrypt") + def test_should_handle_rsa_size_limits(self, mock_encrypt, mock_query): + """Test behavior when token exceeds RSA encryption limits""" + mock_tenant = MagicMock() + mock_tenant.encrypt_public_key = "mock_public_key" + mock_query.return_value.filter.return_value.first.return_value = mock_tenant + + # RSA 2048-bit can only encrypt ~245 bytes + # The actual limit depends on padding scheme + mock_encrypt.side_effect = ValueError("Message too long for RSA key size") + + # Create a token that would exceed RSA limits + long_token = "x" * 300 + + with pytest.raises(ValueError, match="Message too long for RSA key size"): + encrypt_token("tenant-123", long_token) + + @patch("libs.rsa.get_decrypt_decoding") + @patch("libs.rsa.decrypt_token_with_decoding") + def test_batch_decrypt_loads_key_only_once(self, mock_decrypt_with_decoding, mock_get_decoding): + """Verify batch decryption optimization - loads key only once""" + mock_rsa_key = MagicMock() + mock_cipher_rsa = MagicMock() + mock_get_decoding.return_value = (mock_rsa_key, mock_cipher_rsa) + + # Test with multiple tokens + mock_decrypt_with_decoding.side_effect = ["token1", "token2", "token3", "token4", "token5"] + tokens = [base64.b64encode(f"encrypted{i}".encode()).decode() for i in range(5)] + + result = batch_decrypt_token("tenant-123", tokens) + + assert result == ["token1", "token2", "token3", "token4", "token5"] + # Key should only be loaded once regardless of token count + mock_get_decoding.assert_called_once_with("tenant-123") + assert mock_decrypt_with_decoding.call_count == 5 diff --git a/api/tests/unit_tests/extensions/test_redis.py b/api/tests/unit_tests/extensions/test_redis.py new file mode 100644 index 0000000000..933fa32894 --- /dev/null +++ b/api/tests/unit_tests/extensions/test_redis.py @@ -0,0 +1,53 @@ +from redis import RedisError + +from extensions.ext_redis import redis_fallback + + +def test_redis_fallback_success(): + @redis_fallback(default_return=None) + def test_func(): + return "success" + + assert test_func() == "success" + + +def test_redis_fallback_error(): + @redis_fallback(default_return="fallback") + def test_func(): + raise RedisError("Redis error") + + assert test_func() == "fallback" + + +def test_redis_fallback_none_default(): + @redis_fallback() + def test_func(): + raise RedisError("Redis error") + + assert test_func() is None + + +def test_redis_fallback_with_args(): + @redis_fallback(default_return=0) + def test_func(x, y): + raise RedisError("Redis error") + + assert test_func(1, 2) == 0 + + +def test_redis_fallback_with_kwargs(): + @redis_fallback(default_return={}) + def test_func(x=None, y=None): + raise RedisError("Redis error") + + assert test_func(x=1, y=2) == {} + + +def test_redis_fallback_preserves_function_metadata(): + @redis_fallback(default_return=None) + def test_func(): + """Test function docstring""" + pass + + assert test_func.__name__ == "test_func" + assert test_func.__doc__ == "Test function docstring" diff --git a/api/tests/unit_tests/factories/test_variable_factory.py b/api/tests/unit_tests/factories/test_variable_factory.py index 481fbdc91a..edd4c5e93e 100644 --- a/api/tests/unit_tests/factories/test_variable_factory.py +++ b/api/tests/unit_tests/factories/test_variable_factory.py @@ -14,9 +14,7 @@ from core.variables import ( ArrayStringVariable, FloatVariable, IntegerVariable, - ObjectSegment, SecretVariable, - SegmentType, StringVariable, ) from core.variables.exc import VariableError @@ -418,8 +416,6 @@ def test_build_segment_file_array_with_different_file_types(): @st.composite def _generate_file(draw) -> File: - file_id = draw(st.text(min_size=1, max_size=10)) - tenant_id = draw(st.text(min_size=1, max_size=10)) file_type, mime_type, extension = draw( st.sampled_from( [ diff --git a/api/tests/unit_tests/services/test_dataset_service_update_dataset.py b/api/tests/unit_tests/services/test_dataset_service_update_dataset.py index cdbb439c85..87b46f213b 100644 --- a/api/tests/unit_tests/services/test_dataset_service_update_dataset.py +++ b/api/tests/unit_tests/services/test_dataset_service_update_dataset.py @@ -10,7 +10,6 @@ from core.model_runtime.entities.model_entities import ModelType from models.dataset import Dataset, ExternalKnowledgeBindings from services.dataset_service import DatasetService from services.errors.account import NoPermissionError -from tests.unit_tests.conftest import redis_mock class DatasetUpdateTestDataFactory: diff --git a/docker/.env.example b/docker/.env.example index a403f25cb2..29f2ec957a 100644 --- a/docker/.env.example +++ b/docker/.env.example @@ -1138,3 +1138,13 @@ QUEUE_MONITOR_THRESHOLD=200 QUEUE_MONITOR_ALERT_EMAILS= # Monitor interval in minutes, default is 30 minutes QUEUE_MONITOR_INTERVAL=30 + +# Celery schedule tasks configuration +ENABLE_CLEAN_EMBEDDING_CACHE_TASK=false +ENABLE_CLEAN_UNUSED_DATASETS_TASK=false +ENABLE_CREATE_TIDB_SERVERLESS_TASK=false +ENABLE_UPDATE_TIDB_SERVERLESS_STATUS_TASK=false +ENABLE_CLEAN_MESSAGES=false +ENABLE_MAIL_CLEAN_DOCUMENT_NOTIFY_TASK=false +ENABLE_DATASETS_QUEUE_MONITOR=false +ENABLE_CHECK_UPGRADABLE_PLUGIN_TASK=true \ No newline at end of file diff --git a/docker/docker-compose-template.yaml b/docker/docker-compose-template.yaml index fd7c78c7e7..954ba16be1 100644 --- a/docker/docker-compose-template.yaml +++ b/docker/docker-compose-template.yaml @@ -55,6 +55,28 @@ services: - ssrf_proxy_network - default + # worker_beat service + # Celery beat for scheduling periodic tasks. + worker_beat: + image: langgenius/dify-api:1.5.0 + restart: always + environment: + # Use the shared environment variables. + <<: *shared-api-worker-env + # Startup mode, 'worker_beat' starts the Celery beat for scheduling periodic tasks. + MODE: beat + depends_on: + db: + condition: service_healthy + redis: + condition: service_started + volumes: + # Mount the storage directory to the container, for storing user files. + - ./volumes/app/storage:/app/api/storage + networks: + - ssrf_proxy_network + - default + # Frontend web application. web: image: langgenius/dify-web:1.5.1 diff --git a/docker/docker-compose.yaml b/docker/docker-compose.yaml index 0a95251ff0..df495bfa7f 100644 --- a/docker/docker-compose.yaml +++ b/docker/docker-compose.yaml @@ -514,6 +514,14 @@ x-shared-env: &shared-api-worker-env QUEUE_MONITOR_THRESHOLD: ${QUEUE_MONITOR_THRESHOLD:-200} QUEUE_MONITOR_ALERT_EMAILS: ${QUEUE_MONITOR_ALERT_EMAILS:-} QUEUE_MONITOR_INTERVAL: ${QUEUE_MONITOR_INTERVAL:-30} + ENABLE_CLEAN_EMBEDDING_CACHE_TASK: ${ENABLE_CLEAN_EMBEDDING_CACHE_TASK:-false} + ENABLE_CLEAN_UNUSED_DATASETS_TASK: ${ENABLE_CLEAN_UNUSED_DATASETS_TASK:-false} + ENABLE_CREATE_TIDB_SERVERLESS_TASK: ${ENABLE_CREATE_TIDB_SERVERLESS_TASK:-false} + ENABLE_UPDATE_TIDB_SERVERLESS_STATUS_TASK: ${ENABLE_UPDATE_TIDB_SERVERLESS_STATUS_TASK:-false} + ENABLE_CLEAN_MESSAGES: ${ENABLE_CLEAN_MESSAGES:-false} + ENABLE_MAIL_CLEAN_DOCUMENT_NOTIFY_TASK: ${ENABLE_MAIL_CLEAN_DOCUMENT_NOTIFY_TASK:-false} + ENABLE_DATASETS_QUEUE_MONITOR: ${ENABLE_DATASETS_QUEUE_MONITOR:-false} + ENABLE_CHECK_UPGRADABLE_PLUGIN_TASK: ${ENABLE_CHECK_UPGRADABLE_PLUGIN_TASK:-true} services: # API service @@ -571,6 +579,28 @@ services: - ssrf_proxy_network - default + # worker_beat service + # Celery beat for scheduling periodic tasks. + worker_beat: + image: langgenius/dify-api:1.5.0 + restart: always + environment: + # Use the shared environment variables. + <<: *shared-api-worker-env + # Startup mode, 'worker_beat' starts the Celery beat for scheduling periodic tasks. + MODE: beat + depends_on: + db: + condition: service_healthy + redis: + condition: service_started + volumes: + # Mount the storage directory to the container, for storing user files. + - ./volumes/app/storage:/app/api/storage + networks: + - ssrf_proxy_network + - default + # Frontend web application. web: image: langgenius/dify-web:1.5.1 diff --git a/web/app/components/base/chat/chat/question.tsx b/web/app/components/base/chat/chat/question.tsx index 30077125f9..cae8e2b8ce 100644 --- a/web/app/components/base/chat/chat/question.tsx +++ b/web/app/components/base/chat/chat/question.tsx @@ -98,7 +98,7 @@ const Question: FC = ({ return (
-
+
= ({
{ diff --git a/web/app/components/base/icons/src/public/llm/OpenaiTale.json b/web/app/components/base/icons/src/public/llm/OpenaiTale.json new file mode 100644 index 0000000000..b5d5a015ff --- /dev/null +++ b/web/app/components/base/icons/src/public/llm/OpenaiTale.json @@ -0,0 +1,37 @@ +{ + "icon": { + "type": "element", + "isRootNode": true, + "name": "svg", + "attributes": { + "width": "24", + "height": "24", + "viewBox": "0 0 24 24", + "fill": "none", + "xmlns": "http://www.w3.org/2000/svg" + }, + "children": [ + { + "type": "element", + "name": "rect", + "attributes": { + "width": "24", + "height": "24", + "rx": "6", + "fill": "#009688" + }, + "children": [] + }, + { + "type": "element", + "name": "path", + "attributes": { + "d": "M19.7758 11.5959C19.9546 11.9948 20.0681 12.4213 20.1145 12.8563C20.1592 13.2913 20.1369 13.7315 20.044 14.1596C19.9529 14.5878 19.7947 14.9987 19.5746 15.377C19.4302 15.6298 19.2599 15.867 19.0639 16.0854C18.8696 16.3021 18.653 16.4981 18.4174 16.67C18.1801 16.842 17.9274 16.9864 17.6591 17.105C17.3926 17.222 17.1141 17.3114 16.8286 17.3698C16.6945 17.7859 16.4951 18.1797 16.2371 18.5339C15.9809 18.8881 15.6697 19.1993 15.3155 19.4555C14.9613 19.7134 14.5693 19.9129 14.1532 20.047C13.7371 20.1829 13.302 20.2499 12.8636 20.2499C12.573 20.2516 12.2807 20.2207 11.9953 20.1622C11.7116 20.102 11.433 20.0109 11.1665 19.8923C10.9 19.7736 10.6472 19.6258 10.4116 19.4538C10.1778 19.2819 9.96115 19.0841 9.76857 18.8658C9.33871 18.9586 8.89853 18.981 8.46351 18.9363C8.02849 18.8898 7.60207 18.7763 7.20143 18.5975C6.80252 18.4204 6.43284 18.1797 6.10786 17.8857C5.78289 17.5916 5.50606 17.2478 5.28769 16.8695C5.14153 16.6167 5.02117 16.3502 4.93004 16.0734C4.83891 15.7965 4.77873 15.5111 4.74778 15.2205C4.71683 14.9317 4.71855 14.6393 4.7495 14.3488C4.78045 14.0599 4.84407 13.7745 4.9352 13.4976C4.64289 13.1727 4.40217 12.803 4.22335 12.4041C4.04624 12.0034 3.93104 11.5787 3.88634 11.1437C3.83991 10.7087 3.86398 10.2685 3.95511 9.84036C4.04624 9.41222 4.20443 9.00127 4.42452 8.62299C4.56896 8.37023 4.73918 8.13123 4.93348 7.91458C5.12778 7.69793 5.34615 7.50191 5.58171 7.32997C5.81728 7.15802 6.07176 7.01187 6.33827 6.89495C6.6065 6.7763 6.88506 6.68861 7.17048 6.63015C7.3046 6.21232 7.50406 5.82029 7.76026 5.46608C8.01817 5.11188 8.32939 4.80066 8.6836 4.54274C9.03781 4.28654 9.42984 4.08708 9.84595 3.95125C10.2621 3.81713 10.6971 3.74835 11.1355 3.75007C11.4261 3.74835 11.7184 3.77758 12.0039 3.83776C12.2893 3.89794 12.5678 3.98736 12.8344 4.106C13.1009 4.22636 13.3536 4.37251 13.5892 4.54446C13.8248 4.71812 14.0414 4.91414 14.234 5.13251C14.6621 5.04138 15.1023 5.01903 15.5373 5.06373C15.9723 5.10844 16.3971 5.22364 16.7977 5.40074C17.1966 5.57957 17.5663 5.81857 17.8913 6.1126C18.2162 6.4049 18.4931 6.74707 18.7114 7.12707C18.8576 7.37811 18.9779 7.64463 19.0691 7.92318C19.1602 8.20001 19.2221 8.48544 19.2513 8.77602C19.2823 9.06661 19.2823 9.35892 19.2496 9.64951C19.2187 9.94009 19.155 10.2255 19.0639 10.5024C19.3579 10.8273 19.5969 11.1953 19.7758 11.5959ZM14.0466 18.9363C14.4214 18.7815 14.7619 18.5528 15.049 18.2657C15.3362 17.9785 15.5648 17.6381 15.7196 17.2615C15.8743 16.8867 15.9552 16.4843 15.9552 16.0785V12.2442C15.954 12.2407 15.9529 12.2367 15.9517 12.2321C15.9506 12.2287 15.9488 12.2252 15.9466 12.2218C15.9443 12.2184 15.9414 12.2155 15.938 12.2132C15.9345 12.2098 15.9311 12.2075 15.9276 12.2063L14.54 11.4051V16.0373C14.54 16.0837 14.5332 16.1318 14.5211 16.1765C14.5091 16.223 14.4919 16.2659 14.4678 16.3072C14.4438 16.3485 14.4162 16.3863 14.3819 16.419C14.3484 16.4523 14.3109 16.4812 14.2701 16.505L10.9842 18.4015C10.9567 18.4187 10.9103 18.4428 10.8862 18.4565C11.0221 18.5717 11.1699 18.6732 11.3247 18.7626C11.4811 18.852 11.6428 18.9277 11.8113 18.9896C11.9798 19.0497 12.1535 19.0962 12.3288 19.1271C12.5059 19.1581 12.6848 19.1735 12.8636 19.1735C13.2694 19.1735 13.6717 19.0927 14.0466 18.9363ZM6.22135 16.333C6.42596 16.6855 6.69592 16.9916 7.01745 17.2392C7.34071 17.4868 7.70695 17.6673 8.09899 17.7722C8.49102 17.8771 8.90025 17.9046 9.3026 17.8513C9.70495 17.798 10.0918 17.6673 10.4443 17.4644L13.7663 15.5472L13.7749 15.5386C13.7772 15.5363 13.7789 15.5329 13.78 15.5283C13.7823 15.5249 13.7841 15.5214 13.7852 15.518V13.9017L9.77545 16.2212C9.73418 16.2453 9.6912 16.2625 9.64649 16.2763C9.60007 16.2883 9.55364 16.2935 9.5055 16.2935C9.45907 16.2935 9.41265 16.2883 9.36622 16.2763C9.32152 16.2625 9.27681 16.2453 9.23554 16.2212L5.94967 14.323C5.92044 14.3058 5.87746 14.28 5.85339 14.2645C5.82244 14.4416 5.80696 14.6204 5.80696 14.7993C5.80696 14.9781 5.82415 15.1569 5.85511 15.334C5.88605 15.5094 5.9342 15.6831 5.99438 15.8516C6.05628 16.0201 6.13194 16.1817 6.22135 16.3364V16.333ZM5.35818 9.1629C5.15529 9.51539 5.02461 9.90398 4.97131 10.3063C4.918 10.7087 4.94552 11.1162 5.0504 11.51C5.15529 11.902 5.33583 12.2682 5.58343 12.5915C5.83103 12.913 6.13881 13.183 6.48958 13.3859L9.80984 15.3048C9.81328 15.3059 9.81729 15.3071 9.82188 15.3082H9.83391C9.8385 15.3082 9.84251 15.3071 9.84595 15.3048C9.84939 15.3036 9.85283 15.3019 9.85627 15.2996L11.249 14.4949L7.23926 12.1805C7.19971 12.1565 7.16189 12.1272 7.1275 12.0946C7.09418 12.0611 7.06529 12.0236 7.04153 11.9828C7.01917 11.9415 7.00026 11.8985 6.98822 11.8521C6.97619 11.8074 6.96931 11.761 6.97103 11.7128V7.80797C6.80252 7.86987 6.63917 7.94553 6.48442 8.03494C6.32967 8.12607 6.18352 8.22924 6.04596 8.34444C5.91013 8.45965 5.78289 8.58688 5.66769 8.72444C5.55248 8.86028 5.45103 9.00815 5.36162 9.1629H5.35818ZM16.7633 11.8177C16.8046 11.8418 16.8424 11.8693 16.8768 11.9037C16.9094 11.9364 16.9387 11.9742 16.9628 12.0155C16.9851 12.0567 17.004 12.1014 17.0161 12.1461C17.0264 12.1926 17.0332 12.239 17.0315 12.2871V16.192C17.5835 15.9891 18.0649 15.6332 18.4208 15.1655C18.7785 14.6978 18.9934 14.139 19.0433 13.5544C19.0931 12.9698 18.9762 12.3817 18.7046 11.8607C18.4329 11.3397 18.0185 10.9064 17.5095 10.6141L14.1893 8.69521C14.1858 8.69406 14.1818 8.69292 14.1772 8.69177H14.1652C14.1618 8.69292 14.1578 8.69406 14.1532 8.69521C14.1497 8.69636 14.1463 8.69808 14.1429 8.70037L12.757 9.50163L16.7667 11.8177H16.7633ZM18.1475 9.7372H18.1457V9.73892L18.1475 9.7372ZM18.1457 9.73548C18.2455 9.15774 18.1784 8.56281 17.9514 8.02119C17.7262 7.47956 17.3496 7.01359 16.8682 6.67658C16.3867 6.34128 15.8193 6.1487 15.233 6.12291C14.6449 6.09884 14.0638 6.24155 13.5548 6.53386L10.2345 8.45105C10.2311 8.45334 10.2282 8.45621 10.2259 8.45965L10.2191 8.46996C10.2179 8.4734 10.2168 8.47741 10.2156 8.482C10.2145 8.48544 10.2139 8.48945 10.2139 8.49403V10.0966L14.2237 7.78046C14.2649 7.75639 14.3096 7.7392 14.3543 7.72544C14.4008 7.7134 14.4472 7.70825 14.4936 7.70825C14.5418 7.70825 14.5882 7.7134 14.6346 7.72544C14.6793 7.7392 14.7223 7.75639 14.7636 7.78046L18.0494 9.67874C18.0787 9.69593 18.1217 9.72 18.1457 9.73548ZM9.45735 7.96101C9.45735 7.91458 9.46423 7.86816 9.47627 7.82173C9.4883 7.77702 9.5055 7.73232 9.52957 7.69105C9.55364 7.6515 9.58115 7.61368 9.61554 7.57929C9.64821 7.54662 9.68604 7.51739 9.72731 7.49503L13.0132 5.59848C13.0441 5.57957 13.0871 5.55549 13.1112 5.54346C12.6607 5.1669 12.1105 4.92618 11.5276 4.85224C10.9447 4.77658 10.3532 4.86943 9.82188 5.11875C9.28885 5.36807 8.83835 5.76527 8.52369 6.26047C8.20903 6.75739 8.04224 7.33169 8.04224 7.91974V11.7541C8.04339 11.7587 8.04454 11.7627 8.04568 11.7661C8.04683 11.7696 8.04855 11.773 8.05084 11.7765C8.05313 11.7799 8.056 11.7833 8.05944 11.7868C8.06173 11.7891 8.06517 11.7914 8.06976 11.7937L9.45735 12.5949V7.96101ZM10.2105 13.0282L11.997 14.0599L13.7835 13.0282V10.9666L11.9987 9.93493L10.2122 10.9666L10.2105 13.0282Z", + "fill": "white" + }, + "children": [] + } + ] + }, + "name": "OpenaiTale" +} diff --git a/web/app/components/base/icons/src/public/llm/OpenaiTeal.tsx b/web/app/components/base/icons/src/public/llm/OpenaiTale.tsx similarity index 86% rename from web/app/components/base/icons/src/public/llm/OpenaiTeal.tsx rename to web/app/components/base/icons/src/public/llm/OpenaiTale.tsx index ab50b42a1e..e7ae45e293 100644 --- a/web/app/components/base/icons/src/public/llm/OpenaiTeal.tsx +++ b/web/app/components/base/icons/src/public/llm/OpenaiTale.tsx @@ -2,7 +2,7 @@ // DON NOT EDIT IT MANUALLY import * as React from 'react' -import data from './OpenaiTeal.json' +import data from './OpenaiTale.json' import IconBase from '@/app/components/base/icons/IconBase' import type { IconData } from '@/app/components/base/icons/IconBase' @@ -15,6 +15,6 @@ const Icon = ( }, ) => -Icon.displayName = 'OpenaiTeal' +Icon.displayName = 'OpenaiTale' export default Icon diff --git a/web/app/components/base/icons/src/public/llm/index.ts b/web/app/components/base/icons/src/public/llm/index.ts index fa4a1bdd10..289942ab86 100644 --- a/web/app/components/base/icons/src/public/llm/index.ts +++ b/web/app/components/base/icons/src/public/llm/index.ts @@ -28,12 +28,12 @@ export { default as Microsoft } from './Microsoft' export { default as OpenaiBlack } from './OpenaiBlack' export { default as OpenaiBlue } from './OpenaiBlue' export { default as OpenaiGreen } from './OpenaiGreen' -export { default as OpenaiTeal } from './OpenaiTeal' export { default as OpenaiText } from './OpenaiText' export { default as OpenaiTransparent } from './OpenaiTransparent' export { default as OpenaiViolet } from './OpenaiViolet' -export { default as OpenaiYellow } from './OpenaiYellow' +export { default as OpenaiTale } from './OpenaiTale' export { default as OpenllmText } from './OpenllmText' +export { default as OpenaiYellow } from './OpenaiYellow' export { default as Openllm } from './Openllm' export { default as ReplicateText } from './ReplicateText' export { default as Replicate } from './Replicate' diff --git a/web/app/components/plugins/plugin-page/index.tsx b/web/app/components/plugins/plugin-page/index.tsx index a0734790b9..894a8b7f45 100644 --- a/web/app/components/plugins/plugin-page/index.tsx +++ b/web/app/components/plugins/plugin-page/index.tsx @@ -136,7 +136,7 @@ const PluginPage = ({ const options = usePluginPageContext(v => v.options) const activeTab = usePluginPageContext(v => v.activeTab) const setActiveTab = usePluginPageContext(v => v.setActiveTab) - const { enable_marketplace, branding } = useGlobalPublicStore(s => s.systemFeatures) + const { enable_marketplace } = useGlobalPublicStore(s => s.systemFeatures) const isPluginsTab = useMemo(() => activeTab === PLUGIN_PAGE_TABS_MAP.plugins, [activeTab]) const isExploringMarketplace = useMemo(() => { @@ -225,7 +225,7 @@ const PluginPage = ({ ) } { - canSetPermissions && !branding.enabled && ( + canSetPermissions && ( diff --git a/web/app/components/plugins/reference-setting-modal/auto-update-setting/tool-picker.tsx b/web/app/components/plugins/reference-setting-modal/auto-update-setting/tool-picker.tsx index fcd8f64519..5676bc37a0 100644 --- a/web/app/components/plugins/reference-setting-modal/auto-update-setting/tool-picker.tsx +++ b/web/app/components/plugins/reference-setting-modal/auto-update-setting/tool-picker.tsx @@ -113,7 +113,7 @@ const ToolPicker: FC = ({ void @@ -21,6 +23,8 @@ type Props = { } const ClassItem: FC = ({ + className, + headerClassName, nodeId, payload, onChange, @@ -49,6 +53,8 @@ const ClassItem: FC = ({ return ( void readonly?: boolean filterVar: (payload: Var, valueSelector: ValueSelector) => boolean + handleSortTopic?: (newTopics: (Topic & { id: string })[]) => void } const ClassList: FC = ({ @@ -25,6 +29,7 @@ const ClassList: FC = ({ onChange, readonly, filterVar, + handleSortTopic = noop, }) => { const { t } = useTranslation() const { handleEdgeDeleteByDeleteBranch } = useEdgesInteractions() @@ -55,22 +60,48 @@ const ClassList: FC = ({ } }, [list, onChange, handleEdgeDeleteByDeleteBranch, nodeId]) + const topicCount = list.length + const handleSideWidth = 3 // Todo Remove; edit topic name return ( -
+ ({ ...item }))} + setList={handleSortTopic} + handle='.handle' + ghostClass='bg-components-panel-bg' + animation={150} + disabled={readonly} + className='space-y-2' + > { list.map((item, index) => { + const canDrag = (() => { + if (readonly) + return false + + return topicCount >= 2 + })() return ( - +
+
+ +
+
) }) } @@ -81,7 +112,7 @@ const ClassList: FC = ({ /> )} -
+ ) } export default React.memo(ClassList) diff --git a/web/app/components/workflow/nodes/question-classifier/panel.tsx b/web/app/components/workflow/nodes/question-classifier/panel.tsx index 8cf9ec5f7c..8e27f5dceb 100644 --- a/web/app/components/workflow/nodes/question-classifier/panel.tsx +++ b/web/app/components/workflow/nodes/question-classifier/panel.tsx @@ -40,6 +40,7 @@ const Panel: FC> = ({ handleVisionResolutionChange, handleVisionResolutionEnabledChange, filterVar, + handleSortTopic, } = useConfig(id, data) const model = inputs.model @@ -99,6 +100,7 @@ const Panel: FC> = ({ onChange={handleTopicsChange} readonly={readOnly} filterVar={filterVar} + handleSortTopic={handleSortTopic} /> diff --git a/web/app/components/workflow/nodes/question-classifier/use-config.ts b/web/app/components/workflow/nodes/question-classifier/use-config.ts index 8eacf5b43f..a4acf5b7f6 100644 --- a/web/app/components/workflow/nodes/question-classifier/use-config.ts +++ b/web/app/components/workflow/nodes/question-classifier/use-config.ts @@ -9,13 +9,15 @@ import { import { useStore } from '../../store' import useAvailableVarList from '../_base/hooks/use-available-var-list' import useConfigVision from '../../hooks/use-config-vision' -import type { QuestionClassifierNodeType } from './types' +import type { QuestionClassifierNodeType, Topic } from './types' import useNodeCrud from '@/app/components/workflow/nodes/_base/hooks/use-node-crud' import { useModelListAndDefaultModelAndCurrentProviderAndModel } from '@/app/components/header/account-setting/model-provider-page/hooks' import { ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations' import { checkHasQueryBlock } from '@/app/components/base/prompt-editor/constants' +import { useUpdateNodeInternals } from 'reactflow' const useConfig = (id: string, payload: QuestionClassifierNodeType) => { + const updateNodeInternals = useUpdateNodeInternals() const { nodesReadOnly: readOnly } = useNodesReadOnly() const isChatMode = useIsChatMode() const defaultConfig = useStore(s => s.nodesDefaultConfigs)[payload.type] @@ -166,6 +168,17 @@ const useConfig = (id: string, payload: QuestionClassifierNodeType) => { return varPayload.type === VarType.string }, []) + const handleSortTopic = useCallback((newTopics: (Topic & { id: string })[]) => { + const newInputs = produce(inputs, (draft) => { + draft.classes = newTopics.filter(Boolean).map(item => ({ + id: item.id, + name: item.name, + })) + }) + setInputs(newInputs) + updateNodeInternals(id) + }, [id, inputs, setInputs, updateNodeInternals]) + return { readOnly, inputs, @@ -185,6 +198,7 @@ const useConfig = (id: string, payload: QuestionClassifierNodeType) => { isVisionModel, handleVisionResolutionEnabledChange, handleVisionResolutionChange, + handleSortTopic, } } diff --git a/web/i18n/de-DE/app.ts b/web/i18n/de-DE/app.ts index d29a475bcd..52819d0c7e 100644 --- a/web/i18n/de-DE/app.ts +++ b/web/i18n/de-DE/app.ts @@ -174,6 +174,7 @@ const translation = { title: 'Weben', description: 'Weave ist eine Open-Source-Plattform zur Bewertung, Testung und Überwachung von LLM-Anwendungen.', }, + aliyun: {}, }, answerIcon: { descriptionInExplore: 'Gibt an, ob das web app Symbol zum Ersetzen 🤖 in Explore verwendet werden soll', diff --git a/web/i18n/de-DE/workflow.ts b/web/i18n/de-DE/workflow.ts index f7f757f91b..ba49f72b69 100644 --- a/web/i18n/de-DE/workflow.ts +++ b/web/i18n/de-DE/workflow.ts @@ -364,6 +364,7 @@ const translation = { ms: 'Frau', retries: '{{num}} Wiederholungen', }, + typeSwitch: {}, }, start: { required: 'erforderlich', diff --git a/web/i18n/es-ES/app.ts b/web/i18n/es-ES/app.ts index 18741226fa..4c9497e16d 100644 --- a/web/i18n/es-ES/app.ts +++ b/web/i18n/es-ES/app.ts @@ -172,6 +172,7 @@ const translation = { description: 'Weave es una plataforma de código abierto para evaluar, probar y monitorear aplicaciones de LLM.', title: 'Tejer', }, + aliyun: {}, }, answerIcon: { title: 'Usar el icono de la aplicación web para reemplazar 🤖', diff --git a/web/i18n/es-ES/workflow.ts b/web/i18n/es-ES/workflow.ts index 519577150d..44516317e8 100644 --- a/web/i18n/es-ES/workflow.ts +++ b/web/i18n/es-ES/workflow.ts @@ -364,6 +364,7 @@ const translation = { retries: '{{num}} Reintentos', retry: 'Reintentar', }, + typeSwitch: {}, }, start: { required: 'requerido', diff --git a/web/i18n/fa-IR/app.ts b/web/i18n/fa-IR/app.ts index 5e9bd938f2..bf2fa00c11 100644 --- a/web/i18n/fa-IR/app.ts +++ b/web/i18n/fa-IR/app.ts @@ -176,6 +176,7 @@ const translation = { title: 'بافندگی', description: 'ویو یک پلتفرم متن باز برای ارزیابی، آزمایش و نظارت بر برنامه‌های LLM است.', }, + aliyun: {}, }, answerIcon: { descriptionInExplore: 'آیا از نماد web app برای جایگزینی 🤖 در Explore استفاده کنیم یا خیر', diff --git a/web/i18n/fa-IR/workflow.ts b/web/i18n/fa-IR/workflow.ts index 94903c2bd0..800dba06b8 100644 --- a/web/i18n/fa-IR/workflow.ts +++ b/web/i18n/fa-IR/workflow.ts @@ -364,6 +364,7 @@ const translation = { retrySuccessful: 'امتحان مجدد با موفقیت انجام دهید', retryFailedTimes: '{{بار}} تلاش های مجدد ناموفق بود', }, + typeSwitch: {}, }, start: { required: 'الزامی', diff --git a/web/i18n/fr-FR/app.ts b/web/i18n/fr-FR/app.ts index 29d7a9b3de..18cd04a1e1 100644 --- a/web/i18n/fr-FR/app.ts +++ b/web/i18n/fr-FR/app.ts @@ -172,6 +172,7 @@ const translation = { title: 'Tisser', description: 'Weave est une plateforme open-source pour évaluer, tester et surveiller les applications LLM.', }, + aliyun: {}, }, answerIcon: { description: 'S’il faut utiliser l’icône web app pour remplacer 🤖 dans l’application partagée', diff --git a/web/i18n/fr-FR/workflow.ts b/web/i18n/fr-FR/workflow.ts index a008a2a735..8c8180abff 100644 --- a/web/i18n/fr-FR/workflow.ts +++ b/web/i18n/fr-FR/workflow.ts @@ -364,6 +364,7 @@ const translation = { ms: 'ms', retries: '{{num}} Tentatives', }, + typeSwitch: {}, }, start: { required: 'requis', diff --git a/web/i18n/hi-IN/app.ts b/web/i18n/hi-IN/app.ts index 9485d7359b..e9073722f7 100644 --- a/web/i18n/hi-IN/app.ts +++ b/web/i18n/hi-IN/app.ts @@ -172,6 +172,7 @@ const translation = { title: 'बुनना', description: 'वीव एक ओपन-सोर्स प्लेटफ़ॉर्म है जो LLM अनुप्रयोगों का मूल्यांकन, परीक्षण और निगरानी करने के लिए है।', }, + aliyun: {}, }, answerIcon: { title: 'बदलने 🤖 के लिए web app चिह्न का उपयोग करें', diff --git a/web/i18n/hi-IN/workflow.ts b/web/i18n/hi-IN/workflow.ts index 34293d95ba..ffddacaf3a 100644 --- a/web/i18n/hi-IN/workflow.ts +++ b/web/i18n/hi-IN/workflow.ts @@ -376,6 +376,7 @@ const translation = { retry: 'पुनर्प्रयास', retryOnFailure: 'विफलता पर पुनः प्रयास करें', }, + typeSwitch: {}, }, start: { required: 'आवश्यक', diff --git a/web/i18n/it-IT/app.ts b/web/i18n/it-IT/app.ts index feade00168..a08714df71 100644 --- a/web/i18n/it-IT/app.ts +++ b/web/i18n/it-IT/app.ts @@ -184,6 +184,7 @@ const translation = { title: 'Intrecciare', description: 'Weave è una piattaforma open-source per valutare, testare e monitorare le applicazioni LLM.', }, + aliyun: {}, }, answerIcon: { description: 'Se utilizzare l\'icona web app per la sostituzione 🤖 nell\'applicazione condivisa', diff --git a/web/i18n/it-IT/workflow.ts b/web/i18n/it-IT/workflow.ts index 0f1837e084..d7e85dcc19 100644 --- a/web/i18n/it-IT/workflow.ts +++ b/web/i18n/it-IT/workflow.ts @@ -379,6 +379,7 @@ const translation = { retryFailed: 'Nuovo tentativo non riuscito', ms: 'ms', }, + typeSwitch: {}, }, start: { required: 'richiesto', diff --git a/web/i18n/ja-JP/app.ts b/web/i18n/ja-JP/app.ts index 1d94d67eb0..2058b29d9e 100644 --- a/web/i18n/ja-JP/app.ts +++ b/web/i18n/ja-JP/app.ts @@ -180,6 +180,7 @@ const translation = { title: '織る', description: 'Weave は、LLM アプリケーションを評価、テスト、および監視するためのオープンソースプラットフォームです。', }, + aliyun: {}, }, answerIcon: { title: 'Web アプリアイコンを使用して🤖を置き換える', diff --git a/web/i18n/ja-JP/tools.ts b/web/i18n/ja-JP/tools.ts index d69cd4a6f5..f96a5f4182 100644 --- a/web/i18n/ja-JP/tools.ts +++ b/web/i18n/ja-JP/tools.ts @@ -228,7 +228,6 @@ const translation = { publishTip: 'アプリが公開されていません。まずアプリを公開してください。', }, }, - } export default translation diff --git a/web/i18n/ja-JP/workflow.ts b/web/i18n/ja-JP/workflow.ts index e4b31548bf..04702194f8 100644 --- a/web/i18n/ja-JP/workflow.ts +++ b/web/i18n/ja-JP/workflow.ts @@ -369,6 +369,7 @@ const translation = { ms: 'ミリ秒', retries: '再試行回数:{{num}}', }, + typeSwitch: {}, }, start: { required: '必須', diff --git a/web/i18n/ko-KR/app.ts b/web/i18n/ko-KR/app.ts index e9634bfbde..96407f829b 100644 --- a/web/i18n/ko-KR/app.ts +++ b/web/i18n/ko-KR/app.ts @@ -192,6 +192,7 @@ const translation = { description: 'Weave 는 LLM 애플리케이션을 평가하고 테스트하며 모니터링하기 위한 오픈 소스 플랫폼입니다.', }, + aliyun: {}, }, answerIcon: { description: diff --git a/web/i18n/ko-KR/workflow.ts b/web/i18n/ko-KR/workflow.ts index 1270408c6c..6a9f97862e 100644 --- a/web/i18n/ko-KR/workflow.ts +++ b/web/i18n/ko-KR/workflow.ts @@ -388,6 +388,7 @@ const translation = { ms: '미에스', retries: '{{숫자}} 재시도', }, + typeSwitch: {}, }, start: { required: '필수', diff --git a/web/i18n/pl-PL/app.ts b/web/i18n/pl-PL/app.ts index ee422a8b56..141ab190e0 100644 --- a/web/i18n/pl-PL/app.ts +++ b/web/i18n/pl-PL/app.ts @@ -179,6 +179,7 @@ const translation = { title: 'Tkaj', description: 'Weave to platforma open-source do oceny, testowania i monitorowania aplikacji LLM.', }, + aliyun: {}, }, answerIcon: { description: 'Czy w aplikacji udostępnionej ma być używana ikona aplikacji internetowej do zamiany 🤖.', diff --git a/web/i18n/pl-PL/workflow.ts b/web/i18n/pl-PL/workflow.ts index 07c5fa1f92..6d1c9ccc8c 100644 --- a/web/i18n/pl-PL/workflow.ts +++ b/web/i18n/pl-PL/workflow.ts @@ -364,6 +364,7 @@ const translation = { retryFailedTimes: '{{times}} ponawianie prób nie powiodło się', ms: 'Ms', }, + typeSwitch: {}, }, start: { required: 'wymagane', diff --git a/web/i18n/pt-BR/app.ts b/web/i18n/pt-BR/app.ts index 742159692c..099d0a33ea 100644 --- a/web/i18n/pt-BR/app.ts +++ b/web/i18n/pt-BR/app.ts @@ -172,6 +172,7 @@ const translation = { description: 'Weave é uma plataforma de código aberto para avaliar, testar e monitorar aplicações de LLM.', title: 'Trançar', }, + aliyun: {}, }, answerIcon: { descriptionInExplore: 'Se o ícone do web app deve ser usado para substituir 🤖 no Explore', diff --git a/web/i18n/pt-BR/workflow.ts b/web/i18n/pt-BR/workflow.ts index 85b05ef06f..1cb323f59a 100644 --- a/web/i18n/pt-BR/workflow.ts +++ b/web/i18n/pt-BR/workflow.ts @@ -364,6 +364,7 @@ const translation = { ms: 'ms', retries: '{{num}} Tentativas', }, + typeSwitch: {}, }, start: { required: 'requerido', diff --git a/web/i18n/ro-RO/app.ts b/web/i18n/ro-RO/app.ts index 5fdb32945c..2d63bdfba7 100644 --- a/web/i18n/ro-RO/app.ts +++ b/web/i18n/ro-RO/app.ts @@ -172,6 +172,9 @@ const translation = { title: 'Împletește', description: 'Weave este o platformă open-source pentru evaluarea, testarea și monitorizarea aplicațiilor LLM.', }, + aliyun: { + description: 'Platforma de observabilitate SaaS oferită de Alibaba Cloud permite monitorizarea, urmărirea și evaluarea aplicațiilor Dify din cutie.', + }, }, answerIcon: { descriptionInExplore: 'Dacă să utilizați pictograma web app pentru a înlocui 🤖 în Explore', diff --git a/web/i18n/ro-RO/workflow.ts b/web/i18n/ro-RO/workflow.ts index 6942c1eea5..886dc3b790 100644 --- a/web/i18n/ro-RO/workflow.ts +++ b/web/i18n/ro-RO/workflow.ts @@ -364,6 +364,7 @@ const translation = { retries: '{{num}} Încercări', retryTimes: 'Reîncercați {{times}} ori în caz de eșec', }, + typeSwitch: {}, }, start: { required: 'necesar', diff --git a/web/i18n/ru-RU/app.ts b/web/i18n/ru-RU/app.ts index 03283180dc..de8047b080 100644 --- a/web/i18n/ru-RU/app.ts +++ b/web/i18n/ru-RU/app.ts @@ -176,6 +176,7 @@ const translation = { description: 'Weave — это открытая платформа для оценки, тестирования и мониторинга приложений LLM.', title: 'Ткать', }, + aliyun: {}, }, answerIcon: { title: 'Использование значка web app для замены 🤖', diff --git a/web/i18n/ru-RU/workflow.ts b/web/i18n/ru-RU/workflow.ts index dfdbac3ce9..aecd9e652c 100644 --- a/web/i18n/ru-RU/workflow.ts +++ b/web/i18n/ru-RU/workflow.ts @@ -364,6 +364,7 @@ const translation = { retryFailedTimes: 'Повторные попытки {{times}} не увенчались успехом', retries: '{{число}} Повторных попыток', }, + typeSwitch: {}, }, start: { required: 'обязательно', diff --git a/web/i18n/sl-SI/app.ts b/web/i18n/sl-SI/app.ts index bba09351aa..152b7d63dc 100644 --- a/web/i18n/sl-SI/app.ts +++ b/web/i18n/sl-SI/app.ts @@ -181,6 +181,7 @@ const translation = { title: 'Tkanje', description: 'Weave je odprtokodna platforma za vrednotenje, testiranje in spremljanje aplikacij LLM.', }, + aliyun: {}, }, mermaid: { handDrawn: 'Ročno narisano', diff --git a/web/i18n/sl-SI/workflow.ts b/web/i18n/sl-SI/workflow.ts index 16e3ae72cb..a7c2626264 100644 --- a/web/i18n/sl-SI/workflow.ts +++ b/web/i18n/sl-SI/workflow.ts @@ -366,6 +366,7 @@ const translation = { }, insertVarTip: 'Vstavite spremenljivko', outputVars: 'Izhodne spremenljivke', + typeSwitch: {}, }, start: { outputVars: { diff --git a/web/i18n/th-TH/app.ts b/web/i18n/th-TH/app.ts index 3d4809e874..9d2b9af398 100644 --- a/web/i18n/th-TH/app.ts +++ b/web/i18n/th-TH/app.ts @@ -177,6 +177,7 @@ const translation = { title: 'ทอ', description: 'Weave เป็นแพลตฟอร์มโอเพนซอร์สสำหรับการประเมินผล ทดสอบ และตรวจสอบแอปพลิเคชัน LLM', }, + aliyun: {}, }, mermaid: { handDrawn: 'วาดด้วยมือ', diff --git a/web/i18n/th-TH/workflow.ts b/web/i18n/th-TH/workflow.ts index 8d99c1c514..28be5c57e8 100644 --- a/web/i18n/th-TH/workflow.ts +++ b/web/i18n/th-TH/workflow.ts @@ -364,6 +364,7 @@ const translation = { retries: '{{num}} ลอง', ms: 'นางสาว', }, + typeSwitch: {}, }, start: { required: 'ต้องระบุ', diff --git a/web/i18n/tr-TR/app.ts b/web/i18n/tr-TR/app.ts index 639319fd81..16bad22231 100644 --- a/web/i18n/tr-TR/app.ts +++ b/web/i18n/tr-TR/app.ts @@ -172,6 +172,7 @@ const translation = { title: 'Dokuma', description: 'Weave, LLM uygulamalarını değerlendirmek, test etmek ve izlemek için açık kaynaklı bir platformdur.', }, + aliyun: {}, }, answerIcon: { descriptionInExplore: 'Keşfet\'te değiştirilecek 🤖 web app simgesinin kullanılıp kullanılmayacağı', diff --git a/web/i18n/tr-TR/workflow.ts b/web/i18n/tr-TR/workflow.ts index 63eed4bb9c..a09e5d9068 100644 --- a/web/i18n/tr-TR/workflow.ts +++ b/web/i18n/tr-TR/workflow.ts @@ -364,6 +364,7 @@ const translation = { retrying: 'Yeniden deneniyor...', ms: 'Ms', }, + typeSwitch: {}, }, start: { required: 'gerekli', diff --git a/web/i18n/uk-UA/app.ts b/web/i18n/uk-UA/app.ts index 9e1d3c60c6..9786fd36db 100644 --- a/web/i18n/uk-UA/app.ts +++ b/web/i18n/uk-UA/app.ts @@ -172,6 +172,7 @@ const translation = { title: 'Ткати', description: 'Weave є платформою з відкритим кодом для оцінки, тестування та моніторингу LLM додатків.', }, + aliyun: {}, }, answerIcon: { title: 'Використовуйте піктограму web app для заміни 🤖', diff --git a/web/i18n/uk-UA/workflow.ts b/web/i18n/uk-UA/workflow.ts index a6a04246c2..dd61582129 100644 --- a/web/i18n/uk-UA/workflow.ts +++ b/web/i18n/uk-UA/workflow.ts @@ -364,6 +364,7 @@ const translation = { retryFailedTimes: '{{times}} повторні спроби не вдалися', retryTimes: 'Повторіть спробу {{times}} у разі невдачі', }, + typeSwitch: {}, }, start: { required: 'обов\'язковий', diff --git a/web/i18n/vi-VN/app.ts b/web/i18n/vi-VN/app.ts index 0968fcb458..d8f80d9df0 100644 --- a/web/i18n/vi-VN/app.ts +++ b/web/i18n/vi-VN/app.ts @@ -172,6 +172,7 @@ const translation = { title: 'Dệt', description: 'Weave là một nền tảng mã nguồn mở để đánh giá, thử nghiệm và giám sát các ứng dụng LLM.', }, + aliyun: {}, }, answerIcon: { description: 'Có nên sử dụng biểu tượng web app để thay thế 🤖 trong ứng dụng được chia sẻ hay không', diff --git a/web/i18n/vi-VN/workflow.ts b/web/i18n/vi-VN/workflow.ts index 47d8c13f96..05cd279728 100644 --- a/web/i18n/vi-VN/workflow.ts +++ b/web/i18n/vi-VN/workflow.ts @@ -364,6 +364,7 @@ const translation = { times: 'lần', ms: 'Ms', }, + typeSwitch: {}, }, start: { required: 'bắt buộc', diff --git a/web/i18n/zh-Hant/app.ts b/web/i18n/zh-Hant/app.ts index 41cd6324c9..e5f997daff 100644 --- a/web/i18n/zh-Hant/app.ts +++ b/web/i18n/zh-Hant/app.ts @@ -171,6 +171,7 @@ const translation = { title: '編織', description: 'Weave 是一個開源平台,用於評估、測試和監控大型語言模型應用程序。', }, + aliyun: {}, }, answerIcon: { descriptionInExplore: '是否使用 web app 圖示在 Explore 中取代 🤖', diff --git a/web/i18n/zh-Hant/workflow.ts b/web/i18n/zh-Hant/workflow.ts index 3368aee1b7..1d29d2f5ab 100644 --- a/web/i18n/zh-Hant/workflow.ts +++ b/web/i18n/zh-Hant/workflow.ts @@ -364,6 +364,7 @@ const translation = { ms: '毫秒', retries: '{{num}}重試', }, + typeSwitch: {}, }, start: { required: '必填', diff --git a/web/themes/dark.css b/web/themes/dark.css index b7adb61315..d204838e5e 100644 --- a/web/themes/dark.css +++ b/web/themes/dark.css @@ -1,274 +1,278 @@ /* Attention: Generate by code. Don't update by hand!!! */ html[data-theme="dark"] { - --color-components-input-bg-normal: #ffffff14; - --color-components-input-text-placeholder: #c8ceda4d; - --color-components-input-bg-hover: #ffffff08; - --color-components-input-bg-active: #ffffff0d; + --color-components-input-bg-normal: rgb(255 255 255 / 0.08); + --color-components-input-text-placeholder: rgb(200 206 218 / 0.3); + --color-components-input-bg-hover: rgb(255 255 255 / 0.03); + --color-components-input-bg-active: rgb(255 255 255 / 0.05); --color-components-input-border-active: #747481; --color-components-input-border-destructive: #f97066; --color-components-input-text-filled: #f4f4f5; - --color-components-input-bg-destructive: #ffffff03; - --color-components-input-bg-disabled: #ffffff08; - --color-components-input-text-disabled: #c8ceda4d; - --color-components-input-text-filled-disabled: #c8ceda99; + --color-components-input-bg-destructive: rgb(255 255 255 / 0.01); + --color-components-input-bg-disabled: rgb(255 255 255 / 0.03); + --color-components-input-text-disabled: rgb(200 206 218 / 0.3); + --color-components-input-text-filled-disabled: rgb(200 206 218 / 0.6); --color-components-input-border-hover: #3a3a40; --color-components-input-border-active-prompt-1: #36bffa; --color-components-input-border-active-prompt-2: #296dff; - --color-components-kbd-bg-gray: #ffffff08; - --color-components-kbd-bg-white: #ffffff1f; + --color-components-kbd-bg-gray: rgb(255 255 255 / 0.03); + --color-components-kbd-bg-white: rgb(255 255 255 / 0.12); - --color-components-tooltip-bg: #18181bf2; + --color-components-tooltip-bg: rgb(24 24 27 / 0.95); - --color-components-button-primary-text: #fffffff2; + --color-components-button-primary-text: rgb(255 255 255 / 0.95); --color-components-button-primary-bg: #155aef; - --color-components-button-primary-border: #ffffff1f; + --color-components-button-primary-border: rgb(255 255 255 / 0.12); --color-components-button-primary-bg-hover: #296dff; - --color-components-button-primary-border-hover: #ffffff33; - --color-components-button-primary-bg-disabled: #ffffff08; - --color-components-button-primary-border-disabled: #ffffff14; - --color-components-button-primary-text-disabled: #ffffff33; - - --color-components-button-secondary-text: #ffffffcc; - --color-components-button-secondary-text-disabled: #ffffff33; - --color-components-button-secondary-bg: #ffffff1f; - --color-components-button-secondary-bg-hover: #ffffff33; - --color-components-button-secondary-bg-disabled: #ffffff08; - --color-components-button-secondary-border: #ffffff14; - --color-components-button-secondary-border-hover: #ffffff1f; - --color-components-button-secondary-border-disabled: #ffffff0d; + --color-components-button-primary-border-hover: rgb(255 255 255 / 0.2); + --color-components-button-primary-bg-disabled: rgb(255 255 255 / 0.03); + --color-components-button-primary-border-disabled: rgb(255 255 255 / 0.08); + --color-components-button-primary-text-disabled: rgb(255 255 255 / 0.2); + + --color-components-button-secondary-text: rgb(255 255 255 / 0.8); + --color-components-button-secondary-text-disabled: rgb(255 255 255 / 0.2); + --color-components-button-secondary-bg: rgb(255 255 255 / 0.12); + --color-components-button-secondary-bg-hover: rgb(255 255 255 / 0.2); + --color-components-button-secondary-bg-disabled: rgb(255 255 255 / 0.03); + --color-components-button-secondary-border: rgb(255 255 255 / 0.08); + --color-components-button-secondary-border-hover: rgb(255 255 255 / 0.12); + --color-components-button-secondary-border-disabled: rgb(255 255 255 / 0.05); --color-components-button-tertiary-text: #d9d9de; - --color-components-button-tertiary-text-disabled: #ffffff33; - --color-components-button-tertiary-bg: #ffffff14; - --color-components-button-tertiary-bg-hover: #ffffff1f; - --color-components-button-tertiary-bg-disabled: #ffffff08; + --color-components-button-tertiary-text-disabled: rgb(255 255 255 / 0.2); + --color-components-button-tertiary-bg: rgb(255 255 255 / 0.08); + --color-components-button-tertiary-bg-hover: rgb(255 255 255 / 0.12); + --color-components-button-tertiary-bg-disabled: rgb(255 255 255 / 0.03); --color-components-button-ghost-text: #d9d9de; - --color-components-button-ghost-text-disabled: #ffffff33; - --color-components-button-ghost-bg-hover: #c8ceda14; + --color-components-button-ghost-text-disabled: rgb(255 255 255 / 0.2); + --color-components-button-ghost-bg-hover: rgb(200 206 218 / 0.08); - --color-components-button-destructive-primary-text: #fffffff2; - --color-components-button-destructive-primary-text-disabled: #ffffff33; + --color-components-button-destructive-primary-text: rgb(255 255 255 / 0.95); + --color-components-button-destructive-primary-text-disabled: rgb(255 255 255 / 0.2); --color-components-button-destructive-primary-bg: #d92d20; --color-components-button-destructive-primary-bg-hover: #f04438; - --color-components-button-destructive-primary-bg-disabled: #f0443824; - --color-components-button-destructive-primary-border: #ffffff1f; - --color-components-button-destructive-primary-border-hover: #ffffff33; - --color-components-button-destructive-primary-border-disabled: #ffffff14; + --color-components-button-destructive-primary-bg-disabled: rgb(240 68 56 / 0.14); + --color-components-button-destructive-primary-border: rgb(255 255 255 / 0.12); + --color-components-button-destructive-primary-border-hover: rgb(255 255 255 / 0.2); + --color-components-button-destructive-primary-border-disabled: rgb(255 255 255 / 0.08); --color-components-button-destructive-secondary-text: #f97066; - --color-components-button-destructive-secondary-text-disabled: #f0443833; - --color-components-button-destructive-secondary-bg: #ffffff1f; - --color-components-button-destructive-secondary-bg-hover: #f0443824; - --color-components-button-destructive-secondary-bg-disabled: #f0443814; - --color-components-button-destructive-secondary-border: #ffffff14; - --color-components-button-destructive-secondary-border-hover: #ffffff1f; - --color-components-button-destructive-secondary-border-disabled: #f0443814; + --color-components-button-destructive-secondary-text-disabled: rgb(240 68 56 / 0.2); + --color-components-button-destructive-secondary-bg: rgb(255 255 255 / 0.12); + --color-components-button-destructive-secondary-bg-hover: rgb(240 68 56 / 0.14); + --color-components-button-destructive-secondary-bg-disabled: rgb(240 68 56 / 0.08); + --color-components-button-destructive-secondary-border: rgb(255 255 255 / 0.08); + --color-components-button-destructive-secondary-border-hover: rgb(255 255 255 / 0.12); + --color-components-button-destructive-secondary-border-disabled: rgb(240 68 56 / 0.08); --color-components-button-destructive-tertiary-text: #f97066; - --color-components-button-destructive-tertiary-text-disabled: #f0443833; - --color-components-button-destructive-tertiary-bg: #f0443824; - --color-components-button-destructive-tertiary-bg-hover: #f0443840; - --color-components-button-destructive-tertiary-bg-disabled: #f0443814; + --color-components-button-destructive-tertiary-text-disabled: rgb(240 68 56 / 0.2); + --color-components-button-destructive-tertiary-bg: rgb(240 68 56 / 0.14); + --color-components-button-destructive-tertiary-bg-hover: rgb(240 68 56 / 0.25); + --color-components-button-destructive-tertiary-bg-disabled: rgb(240 68 56 / 0.08); --color-components-button-destructive-ghost-text: #f97066; - --color-components-button-destructive-ghost-text-disabled: #f0443833; - --color-components-button-destructive-ghost-bg-hover: #f0443824; - - --color-components-button-secondary-accent-text: #ffffffcc; - --color-components-button-secondary-accent-text-disabled: #ffffff33; - --color-components-button-secondary-accent-bg: #ffffff0d; - --color-components-button-secondary-accent-bg-hover: #ffffff14; - --color-components-button-secondary-accent-bg-disabled: #ffffff08; - --color-components-button-secondary-accent-border: #ffffff14; - --color-components-button-secondary-accent-border-hover: #ffffff1f; - --color-components-button-secondary-accent-border-disabled: #ffffff0d; + --color-components-button-destructive-ghost-text-disabled: rgb(240 68 56 / 0.2); + --color-components-button-destructive-ghost-bg-hover: rgb(240 68 56 / 0.14); + + --color-components-button-secondary-accent-text: rgb(255 255 255 / 0.8); + --color-components-button-secondary-accent-text-disabled: rgb(255 255 255 / 0.2); + --color-components-button-secondary-accent-bg: rgb(255 255 255 / 0.05); + --color-components-button-secondary-accent-bg-hover: rgb(255 255 255 / 0.08); + --color-components-button-secondary-accent-bg-disabled: rgb(255 255 255 / 0.03); + --color-components-button-secondary-accent-border: rgb(255 255 255 / 0.08); + --color-components-button-secondary-accent-border-hover: rgb(255 255 255 / 0.12); + --color-components-button-secondary-accent-border-disabled: rgb(255 255 255 / 0.05); --color-components-button-indigo-bg: #444ce7; --color-components-button-indigo-bg-hover: #6172f3; - --color-components-button-indigo-bg-disabled: #ffffff08; + --color-components-button-indigo-bg-disabled: rgb(255 255 255 / 0.03); - --color-components-checkbox-icon: #fffffff2; - --color-components-checkbox-icon-disabled: #ffffff33; + --color-components-checkbox-icon: rgb(255 255 255 / 0.95); + --color-components-checkbox-icon-disabled: rgb(255 255 255 / 0.2); --color-components-checkbox-bg: #296dff; --color-components-checkbox-bg-hover: #5289ff; - --color-components-checkbox-bg-disabled: #ffffff08; - --color-components-checkbox-border: #ffffff66; - --color-components-checkbox-border-hover: #ffffff99; - --color-components-checkbox-border-disabled: #ffffff03; - --color-components-checkbox-bg-unchecked: #ffffff08; - --color-components-checkbox-bg-unchecked-hover: #ffffff0d; - --color-components-checkbox-bg-disabled-checked: #155aef33; + --color-components-checkbox-bg-disabled: rgb(255 255 255 / 0.03); + --color-components-checkbox-border: rgb(255 255 255 / 0.4); + --color-components-checkbox-border-hover: rgb(255 255 255 / 0.6); + --color-components-checkbox-border-disabled: rgb(255 255 255 / 0.01); + --color-components-checkbox-bg-unchecked: rgb(255 255 255 / 0.03); + --color-components-checkbox-bg-unchecked-hover: rgb(255 255 255 / 0.05); + --color-components-checkbox-bg-disabled-checked: rgb(21 90 239 / 0.2); --color-components-radio-border-checked: #296dff; --color-components-radio-border-checked-hover: #5289ff; - --color-components-radio-border-checked-disabled: #155aef33; - --color-components-radio-bg-disabled: #ffffff08; - --color-components-radio-border: #ffffff66; - --color-components-radio-border-hover: #ffffff99; - --color-components-radio-border-disabled: #ffffff03; - --color-components-radio-bg: #ffffff00; - --color-components-radio-bg-hover: #ffffff0d; + --color-components-radio-border-checked-disabled: rgb(21 90 239 / 0.2); + --color-components-radio-bg-disabled: rgb(255 255 255 / 0.03); + --color-components-radio-border: rgb(255 255 255 / 0.4); + --color-components-radio-border-hover: rgb(255 255 255 / 0.6); + --color-components-radio-border-disabled: rgb(255 255 255 / 0.01); + --color-components-radio-bg: rgb(255 255 255 / 0); + --color-components-radio-bg-hover: rgb(255 255 255 / 0.05); --color-components-toggle-knob: #f4f4f5; - --color-components-toggle-knob-disabled: #ffffff33; + --color-components-toggle-knob-disabled: rgb(255 255 255 / 0.2); --color-components-toggle-bg: #296dff; --color-components-toggle-bg-hover: #5289ff; - --color-components-toggle-bg-disabled: #ffffff14; - --color-components-toggle-bg-unchecked: #ffffff33; - --color-components-toggle-bg-unchecked-hover: #ffffff4d; - --color-components-toggle-bg-unchecked-disabled: #ffffff14; + --color-components-toggle-bg-disabled: rgb(255 255 255 / 0.08); + --color-components-toggle-bg-unchecked: rgb(255 255 255 / 0.2); + --color-components-toggle-bg-unchecked-hover: rgb(255 255 255 / 0.3); + --color-components-toggle-bg-unchecked-disabled: rgb(255 255 255 / 0.08); --color-components-toggle-knob-hover: #fefefe; --color-components-card-bg: #222225; - --color-components-card-border: #ffffff08; + --color-components-card-border: rgb(255 255 255 / 0.03); --color-components-card-bg-alt: #27272b; + --color-components-card-bg-transparent: rgb(34 34 37 / 0); + --color-components-card-bg-alt-transparent: rgb(39 39 43 / 0); - --color-components-menu-item-text: #c8ceda99; - --color-components-menu-item-text-active: #fffffff2; - --color-components-menu-item-text-hover: #c8cedacc; - --color-components-menu-item-text-active-accent: #fffffff2; + --color-components-menu-item-text: rgb(200 206 218 / 0.6); + --color-components-menu-item-text-active: rgb(255 255 255 / 0.95); + --color-components-menu-item-text-hover: rgb(200 206 218 / 0.8); + --color-components-menu-item-text-active-accent: rgb(255 255 255 / 0.95); + --color-components-menu-item-bg-active: rgb(200 206 218 / 0.14); + --color-components-menu-item-bg-hover: rgb(200 206 218 / 0.08); --color-components-panel-bg: #222225; - --color-components-panel-bg-blur: #2c2c30f2; - --color-components-panel-border: #c8ceda24; - --color-components-panel-border-subtle: #c8ceda14; + --color-components-panel-bg-blur: rgb(44 44 48 / 0.95); + --color-components-panel-border: rgb(200 206 218 / 0.14); + --color-components-panel-border-subtle: rgb(200 206 218 / 0.08); --color-components-panel-gradient-2: #222225; --color-components-panel-gradient-1: #27272b; --color-components-panel-bg-alt: #222225; --color-components-panel-on-panel-item-bg: #27272b; --color-components-panel-on-panel-item-bg-hover: #3a3a40; --color-components-panel-on-panel-item-bg-alt: #3a3a40; - --color-components-panel-on-panel-item-bg-transparent: #2c2c30f2; - --color-components-panel-on-panel-item-bg-hover-transparent: #3a3a4000; - --color-components-panel-on-panel-item-bg-destructive-hover-transparent: #fffbfa00; + --color-components-panel-on-panel-item-bg-transparent: rgb(44 44 48 / 0.95); + --color-components-panel-on-panel-item-bg-hover-transparent: rgb(58 58 64 / 0); + --color-components-panel-on-panel-item-bg-destructive-hover-transparent: rgb(255 251 250 / 0); - --color-components-panel-bg-transparent: #22222500; + --color-components-panel-bg-transparent: rgb(34 34 37 / 0); - --color-components-main-nav-nav-button-text: #c8ceda99; + --color-components-main-nav-nav-button-text: rgb(200 206 218 / 0.6); --color-components-main-nav-nav-button-text-active: #f4f4f5; - --color-components-main-nav-nav-button-bg: #ffffff00; - --color-components-main-nav-nav-button-bg-active: #c8ceda24; - --color-components-main-nav-nav-button-border: #ffffff14; - --color-components-main-nav-nav-button-bg-hover: #c8ceda0a; + --color-components-main-nav-nav-button-bg: rgb(255 255 255 / 0); + --color-components-main-nav-nav-button-bg-active: rgb(200 206 218 / 0.14); + --color-components-main-nav-nav-button-border: rgb(255 255 255 / 0.08); + --color-components-main-nav-nav-button-bg-hover: rgb(200 206 218 / 0.04); - --color-components-main-nav-nav-user-border: #ffffff0d; + --color-components-main-nav-nav-user-border: rgb(255 255 255 / 0.05); --color-components-slider-knob: #f4f4f5; --color-components-slider-knob-hover: #fefefe; - --color-components-slider-knob-disabled: #ffffff33; + --color-components-slider-knob-disabled: rgb(255 255 255 / 0.2); --color-components-slider-range: #296dff; - --color-components-slider-track: #ffffff33; - --color-components-slider-knob-border-hover: #1018284d; - --color-components-slider-knob-border: #10182833; - - --color-components-segmented-control-item-active-bg: #ffffff14; - --color-components-segmented-control-item-active-border: #c8ceda14; - --color-components-segmented-control-bg-normal: #18181bb3; - --color-components-segmented-control-item-active-accent-bg: #155aef33; - --color-components-segmented-control-item-active-accent-border: #155aef4d; - - --color-components-option-card-option-bg: #c8ceda0a; - --color-components-option-card-option-selected-bg: #ffffff0d; + --color-components-slider-track: rgb(255 255 255 / 0.2); + --color-components-slider-knob-border-hover: rgb(16 24 40 / 0.3); + --color-components-slider-knob-border: rgb(16 24 40 / 0.2); + + --color-components-segmented-control-item-active-bg: rgb(255 255 255 / 0.08); + --color-components-segmented-control-item-active-border: rgb(200 206 218 / 0.08); + --color-components-segmented-control-bg-normal: rgb(24 24 27 / 0.7); + --color-components-segmented-control-item-active-accent-bg: rgb(21 90 239 / 0.2); + --color-components-segmented-control-item-active-accent-border: rgb(21 90 239 / 0.3); + + --color-components-option-card-option-bg: rgb(200 206 218 / 0.04); + --color-components-option-card-option-selected-bg: rgb(255 255 255 / 0.05); --color-components-option-card-option-selected-border: #5289ff; - --color-components-option-card-option-border: #c8ceda33; - --color-components-option-card-option-bg-hover: #c8ceda24; - --color-components-option-card-option-border-hover: #c8ceda4d; + --color-components-option-card-option-border: rgb(200 206 218 / 0.2); + --color-components-option-card-option-bg-hover: rgb(200 206 218 / 0.14); + --color-components-option-card-option-border-hover: rgb(200 206 218 / 0.3); --color-components-tab-active: #296dff; - --color-components-badge-white-to-dark: #18181bcc; + --color-components-badge-white-to-dark: rgb(24 24 27 / 0.8); --color-components-badge-status-light-success-bg: #17b26a; --color-components-badge-status-light-success-border-inner: #47cd89; - --color-components-badge-status-light-success-halo: #17b26a4d; + --color-components-badge-status-light-success-halo: rgb(23 178 106 / 0.3); --color-components-badge-status-light-border-outer: #222225; - --color-components-badge-status-light-high-light: #ffffff4d; + --color-components-badge-status-light-high-light: rgb(255 255 255 / 0.3); --color-components-badge-status-light-warning-bg: #f79009; --color-components-badge-status-light-warning-border-inner: #fdb022; - --color-components-badge-status-light-warning-halo: #f790094d; + --color-components-badge-status-light-warning-halo: rgb(247 144 9 / 0.3); --color-components-badge-status-light-error-bg: #f04438; --color-components-badge-status-light-error-border-inner: #f97066; - --color-components-badge-status-light-error-halo: #f044384d; + --color-components-badge-status-light-error-halo: rgb(240 68 56 / 0.3); --color-components-badge-status-light-normal-bg: #0ba5ec; --color-components-badge-status-light-normal-border-inner: #36bffa; - --color-components-badge-status-light-normal-halo: #0ba5ec4d; + --color-components-badge-status-light-normal-halo: rgb(11 165 236 / 0.3); --color-components-badge-status-light-disabled-bg: #676f83; --color-components-badge-status-light-disabled-border-inner: #98a2b2; - --color-components-badge-status-light-disabled-halo: #c8ceda14; + --color-components-badge-status-light-disabled-halo: rgb(200 206 218 / 0.08); - --color-components-badge-bg-green-soft: #17b26a24; - --color-components-badge-bg-orange-soft: #f7900924; - --color-components-badge-bg-red-soft: #f0443824; - --color-components-badge-bg-blue-light-soft: #0ba5ec24; - --color-components-badge-bg-gray-soft: #c8ceda14; - --color-components-badge-bg-dimm: #ffffff08; + --color-components-badge-bg-green-soft: rgb(23 178 106 / 0.14); + --color-components-badge-bg-orange-soft: rgb(247 144 9 / 0.14); + --color-components-badge-bg-red-soft: rgb(240 68 56 / 0.14); + --color-components-badge-bg-blue-light-soft: rgb(11 165 236 / 0.14); + --color-components-badge-bg-gray-soft: rgb(200 206 218 / 0.08); + --color-components-badge-bg-dimm: rgb(255 255 255 / 0.03); --color-components-chart-line: #5289ff; - --color-components-chart-area-1: #155aef33; - --color-components-chart-area-2: #155aef0a; + --color-components-chart-area-1: rgb(21 90 239 / 0.2); + --color-components-chart-area-2: rgb(21 90 239 / 0.04); --color-components-chart-current-1: #5289ff; - --color-components-chart-current-2: #155aef4d; - --color-components-chart-bg: #18181bf2; + --color-components-chart-current-2: rgb(21 90 239 / 0.3); + --color-components-chart-bg: rgb(24 24 27 / 0.95); --color-components-actionbar-bg: #222225; - --color-components-actionbar-border: #c8ceda14; + --color-components-actionbar-border: rgb(200 206 218 / 0.08); --color-components-actionbar-bg-accent: #27272b; --color-components-actionbar-border-accent: #5289ff; - --color-components-dropzone-bg-alt: #18181bcc; - --color-components-dropzone-bg: #18181b66; - --color-components-dropzone-bg-accent: #155aef33; - --color-components-dropzone-border: #c8ceda24; - --color-components-dropzone-border-alt: #c8ceda33; + --color-components-dropzone-bg-alt: rgb(24 24 27 / 0.8); + --color-components-dropzone-bg: rgb(24 24 27 / 0.4); + --color-components-dropzone-bg-accent: rgb(21 90 239 / 0.2); + --color-components-dropzone-border: rgb(200 206 218 / 0.14); + --color-components-dropzone-border-alt: rgb(200 206 218 / 0.2); --color-components-dropzone-border-accent: #84abff; --color-components-progress-brand-progress: #5289ff; --color-components-progress-brand-border: #5289ff; - --color-components-progress-brand-bg: #155aef0a; + --color-components-progress-brand-bg: rgb(21 90 239 / 0.04); --color-components-progress-white-progress: #ffffff; - --color-components-progress-white-border: #fffffff2; - --color-components-progress-white-bg: #ffffff03; + --color-components-progress-white-border: rgb(255 255 255 / 0.95); + --color-components-progress-white-bg: rgb(255 255 255 / 0.01); --color-components-progress-gray-progress: #98a2b2; --color-components-progress-gray-border: #98a2b2; - --color-components-progress-gray-bg: #c8ceda05; + --color-components-progress-gray-bg: rgb(200 206 218 / 0.02); --color-components-progress-warning-progress: #fdb022; --color-components-progress-warning-border: #fdb022; - --color-components-progress-warning-bg: #f790090a; + --color-components-progress-warning-bg: rgb(247 144 9 / 0.04); --color-components-progress-error-progress: #f97066; --color-components-progress-error-border: #f97066; - --color-components-progress-error-bg: #f044380a; + --color-components-progress-error-bg: rgb(240 68 56 / 0.04); - --color-components-chat-input-audio-bg: #155aef33; - --color-components-chat-input-audio-wave-default: #c8ceda24; - --color-components-chat-input-bg-mask-1: #18181b0a; - --color-components-chat-input-bg-mask-2: #18181b99; - --color-components-chat-input-border: #c8ceda33; + --color-components-chat-input-audio-bg: rgb(21 90 239 / 0.2); + --color-components-chat-input-audio-wave-default: rgb(200 206 218 / 0.14); + --color-components-chat-input-bg-mask-1: rgb(24 24 27 / 0.04); + --color-components-chat-input-bg-mask-2: rgb(24 24 27 / 0.6); + --color-components-chat-input-border: rgb(200 206 218 / 0.2); --color-components-chat-input-audio-wave-active: #84abff; - --color-components-chat-input-audio-bg-alt: #18181be6; + --color-components-chat-input-audio-bg-alt: rgb(24 24 27 / 0.9); - --color-components-avatar-shape-fill-stop-0: #fffffff2; - --color-components-avatar-shape-fill-stop-100: #ffffffcc; + --color-components-avatar-shape-fill-stop-0: rgb(255 255 255 / 0.95); + --color-components-avatar-shape-fill-stop-100: rgb(255 255 255 / 0.8); - --color-components-avatar-bg-mask-stop-0: #ffffff33; - --color-components-avatar-bg-mask-stop-100: #ffffff08; + --color-components-avatar-bg-mask-stop-0: rgb(255 255 255 / 0.2); + --color-components-avatar-bg-mask-stop-100: rgb(255 255 255 / 0.03); --color-components-avatar-default-avatar-bg: #222225; - --color-components-avatar-mask-darkmode-dimmed: #0000001f; + --color-components-avatar-mask-darkmode-dimmed: rgb(0 0 0 / 0.12); - --color-components-label-gray: #c8ceda24; + --color-components-label-gray: rgb(200 206 218 / 0.14); --color-components-premium-badge-blue-bg-stop-0: #5289ff; --color-components-premium-badge-blue-bg-stop-100: #296dff; - --color-components-premium-badge-blue-stroke-stop-0: #ffffff33; + --color-components-premium-badge-blue-stroke-stop-0: rgb(255 255 255 / 0.2); --color-components-premium-badge-blue-stroke-stop-100: #296dff; --color-components-premium-badge-blue-text-stop-0: #eff4ff; --color-components-premium-badge-blue-text-stop-100: #b2caff; @@ -276,14 +280,14 @@ html[data-theme="dark"] { --color-components-premium-badge-blue-bg-stop-0-hover: #84abff; --color-components-premium-badge-blue-bg-stop-100-hover: #004aeb; --color-components-premium-badge-blue-glow-hover: #d1e0ff; - --color-components-premium-badge-blue-stroke-stop-0-hover: #ffffff80; + --color-components-premium-badge-blue-stroke-stop-0-hover: rgb(255 255 255 / 0.5); --color-components-premium-badge-blue-stroke-stop-100-hover: #296dff; - --color-components-premium-badge-highlight-stop-0: #ffffff1f; - --color-components-premium-badge-highlight-stop-100: #ffffff33; + --color-components-premium-badge-highlight-stop-0: rgb(255 255 255 / 0.12); + --color-components-premium-badge-highlight-stop-100: rgb(255 255 255 / 0.2); --color-components-premium-badge-indigo-bg-stop-0: #6172f3; --color-components-premium-badge-indigo-bg-stop-100: #3538cd; - --color-components-premium-badge-indigo-stroke-stop-0: #ffffff33; + --color-components-premium-badge-indigo-stroke-stop-0: rgb(255 255 255 / 0.2); --color-components-premium-badge-indigo-stroke-stop-100: #444ce7; --color-components-premium-badge-indigo-text-stop-0: #eef4ff; --color-components-premium-badge-indigo-text-stop-100: #c7d7fe; @@ -291,12 +295,12 @@ html[data-theme="dark"] { --color-components-premium-badge-indigo-glow-hover: #e0eaff; --color-components-premium-badge-indigo-bg-stop-0-hover: #a4bcfd; --color-components-premium-badge-indigo-bg-stop-100-hover: #3538cd; - --color-components-premium-badge-indigo-stroke-stop-0-hover: #ffffff80; + --color-components-premium-badge-indigo-stroke-stop-0-hover: rgb(255 255 255 / 0.5); --color-components-premium-badge-indigo-stroke-stop-100-hover: #444ce7; --color-components-premium-badge-grey-bg-stop-0: #676f83; --color-components-premium-badge-grey-bg-stop-100: #495464; - --color-components-premium-badge-grey-stroke-stop-0: #ffffff1f; + --color-components-premium-badge-grey-stroke-stop-0: rgb(255 255 255 / 0.12); --color-components-premium-badge-grey-stroke-stop-100: #495464; --color-components-premium-badge-grey-text-stop-0: #f9fafb; --color-components-premium-badge-grey-text-stop-100: #e9ebf0; @@ -304,12 +308,12 @@ html[data-theme="dark"] { --color-components-premium-badge-grey-glow-hover: #f2f4f7; --color-components-premium-badge-grey-bg-stop-0-hover: #98a2b2; --color-components-premium-badge-grey-bg-stop-100-hover: #354052; - --color-components-premium-badge-grey-stroke-stop-0-hover: #ffffff80; + --color-components-premium-badge-grey-stroke-stop-0-hover: rgb(255 255 255 / 0.5); --color-components-premium-badge-grey-stroke-stop-100-hover: #676f83; --color-components-premium-badge-orange-bg-stop-0: #ff692e; --color-components-premium-badge-orange-bg-stop-100: #e04f16; - --color-components-premium-badge-orange-stroke-stop-0: #ffffff33; + --color-components-premium-badge-orange-stroke-stop-0: rgb(255 255 255 / 0.2); --color-components-premium-badge-orange-stroke-stop-100: #ff4405; --color-components-premium-badge-orange-text-stop-0: #fef6ee; --color-components-premium-badge-orange-text-stop-100: #f9dbaf; @@ -317,14 +321,14 @@ html[data-theme="dark"] { --color-components-premium-badge-orange-glow-hover: #fdead7; --color-components-premium-badge-orange-bg-stop-0-hover: #ff692e; --color-components-premium-badge-orange-bg-stop-100-hover: #b93815; - --color-components-premium-badge-orange-stroke-stop-0-hover: #ffffff80; + --color-components-premium-badge-orange-stroke-stop-0-hover: rgb(255 255 255 / 0.5); --color-components-premium-badge-orange-stroke-stop-100-hover: #ff4405; - --color-components-progress-bar-bg: #c8ceda14; - --color-components-progress-bar-progress: #c8ceda24; - --color-components-progress-bar-border: #ffffff08; - --color-components-progress-bar-progress-solid: #fffffff2; - --color-components-progress-bar-progress-highlight: #c8ceda33; + --color-components-progress-bar-bg: rgb(200 206 218 / 0.08); + --color-components-progress-bar-progress: rgb(200 206 218 / 0.14); + --color-components-progress-bar-border: rgb(255 255 255 / 0.03); + --color-components-progress-bar-progress-solid: rgb(255 255 255 / 0.95); + --color-components-progress-bar-progress-highlight: rgb(200 206 218 / 0.2); --color-components-icon-bg-red-solid: #d92d20; --color-components-icon-bg-rose-solid: #e31b54; @@ -338,25 +342,25 @@ html[data-theme="dark"] { --color-components-icon-bg-indigo-solid: #444ce7; --color-components-icon-bg-violet-solid: #7839ee; --color-components-icon-bg-midnight-solid: #5d698d; - --color-components-icon-bg-rose-soft: #f63d6833; - --color-components-icon-bg-pink-soft: #ee46bc33; - --color-components-icon-bg-orange-dark-soft: #ff440533; - --color-components-icon-bg-yellow-soft: #eaaa0833; - --color-components-icon-bg-green-soft: #66c61c33; - --color-components-icon-bg-teal-soft: #15b79e33; - --color-components-icon-bg-blue-light-soft: #0ba5ec33; - --color-components-icon-bg-blue-soft: #155aef33; - --color-components-icon-bg-indigo-soft: #6172f333; - --color-components-icon-bg-violet-soft: #875bf733; - --color-components-icon-bg-midnight-soft: #828dad33; - --color-components-icon-bg-red-soft: #f0443833; + --color-components-icon-bg-rose-soft: rgb(246 61 104 / 0.2); + --color-components-icon-bg-pink-soft: rgb(238 70 188 / 0.2); + --color-components-icon-bg-orange-dark-soft: rgb(255 68 5 / 0.2); + --color-components-icon-bg-yellow-soft: rgb(234 170 8 / 0.2); + --color-components-icon-bg-green-soft: rgb(102 198 28 / 0.2); + --color-components-icon-bg-teal-soft: rgb(21 183 158 / 0.2); + --color-components-icon-bg-blue-light-soft: rgb(11 165 236 / 0.2); + --color-components-icon-bg-blue-soft: rgb(21 90 239 / 0.2); + --color-components-icon-bg-indigo-soft: rgb(97 114 243 / 0.2); + --color-components-icon-bg-violet-soft: rgb(135 91 247 / 0.2); + --color-components-icon-bg-midnight-soft: rgb(130 141 173 / 0.2); + --color-components-icon-bg-red-soft: rgb(240 68 56 / 0.2); --color-components-icon-bg-orange-solid: #f79009; - --color-components-icon-bg-orange-soft: #f7900933; + --color-components-icon-bg-orange-soft: rgb(247 144 9 / 0.2); --color-text-primary: #fbfbfc; --color-text-secondary: #d9d9de; - --color-text-tertiary: #c8ceda99; - --color-text-quaternary: #c8ceda66; + --color-text-tertiary: rgb(200 206 218 / 0.6); + --color-text-quaternary: rgb(200 206 218 / 0.4); --color-text-destructive: #f97066; --color-text-success: #17b26a; --color-text-warning: #f79009; @@ -364,80 +368,85 @@ html[data-theme="dark"] { --color-text-success-secondary: #47cd89; --color-text-warning-secondary: #fdb022; --color-text-accent: #5289ff; - --color-text-primary-on-surface: #fffffff2; - --color-text-placeholder: #c8ceda4d; - --color-text-disabled: #c8ceda4d; + --color-text-primary-on-surface: rgb(255 255 255 / 0.95); + --color-text-placeholder: rgb(200 206 218 / 0.3); + --color-text-disabled: rgb(200 206 218 / 0.3); --color-text-accent-secondary: #84abff; --color-text-accent-light-mode-only: #d9d9de; - --color-text-text-selected: #155aef4d; - --color-text-secondary-on-surface: #ffffffe6; + --color-text-text-selected: rgb(21 90 239 / 0.3); + --color-text-secondary-on-surface: rgb(255 255 255 / 0.9); --color-text-logo-text: #e9e9ec; - --color-text-empty-state-icon: #c8ceda4d; + --color-text-empty-state-icon: rgb(200 206 218 / 0.3); --color-text-inverted: #ffffff; - --color-text-inverted-dimmed: #ffffffcc; + --color-text-inverted-dimmed: rgb(255 255 255 / 0.8); --color-background-body: #1d1d20; --color-background-default-subtle: #222225; --color-background-neutral-subtle: #1d1d20; - --color-background-sidenav-bg: #27272aeb; + --color-background-sidenav-bg: rgb(39 39 42 / 0.92); --color-background-default: #222225; - --color-background-soft: #18181b40; + --color-background-soft: rgb(24 24 27 / 0.25); --color-background-gradient-bg-fill-chat-bg-1: #222225; --color-background-gradient-bg-fill-chat-bg-2: #1d1d20; - --color-background-gradient-bg-fill-chat-bubble-bg-1: #c8ceda14; - --color-background-gradient-bg-fill-chat-bubble-bg-2: #c8ceda05; - --color-background-gradient-bg-fill-chat-bubble-bg-3: #27314d; - --color-background-gradient-bg-fill-debug-bg-1: #c8ceda14; - --color-background-gradient-bg-fill-debug-bg-2: #18181b0a; - - --color-background-gradient-mask-gray: #18181b14; - --color-background-gradient-mask-transparent: #00000000; - --color-background-gradient-mask-input-clear-2: #393a3e00; + --color-background-gradient-bg-fill-chat-bubble-bg-1: rgb(200 206 218 / 0.08); + --color-background-gradient-bg-fill-chat-bubble-bg-2: rgb(200 206 218 / 0.02); + --color-background-gradient-bg-fill-debug-bg-1: rgb(200 206 218 / 0.08); + --color-background-gradient-bg-fill-debug-bg-2: rgb(24 24 27 / 0.04); + + --color-background-gradient-mask-gray: rgb(24 24 27 / 0.08); + --color-background-gradient-mask-transparent: rgb(0 0 0 / 0); + --color-background-gradient-mask-input-clear-2: rgb(57 58 62 / 0); --color-background-gradient-mask-input-clear-1: #393a3e; - --color-background-gradient-mask-transparent-dark: #00000000; - --color-background-gradient-mask-side-panel-2: #18181be6; - --color-background-gradient-mask-side-panel-1: #18181b0a; + --color-background-gradient-mask-transparent-dark: rgb(0 0 0 / 0); + --color-background-gradient-mask-side-panel-2: rgb(24 24 27 / 0.9); + --color-background-gradient-mask-side-panel-1: rgb(24 24 27 / 0.04); --color-background-default-burn: #1d1d20; - --color-background-overlay-fullscreen: #27272af7; - --color-background-default-lighter: #c8ceda0a; - --color-background-section: #18181b66; - --color-background-interaction-from-bg-1: #18181b66; - --color-background-interaction-from-bg-2: #18181b24; - --color-background-section-burn: #18181b99; + --color-background-overlay-fullscreen: rgb(39 39 42 / 0.97); + --color-background-default-lighter: rgb(200 206 218 / 0.04); + --color-background-section: rgb(24 24 27 / 0.4); + --color-background-interaction-from-bg-1: rgb(24 24 27 / 0.4); + --color-background-interaction-from-bg-2: rgb(24 24 27 / 0.14); + --color-background-section-burn: rgb(24 24 27 / 0.6); --color-background-default-dodge: #3a3a40; - --color-background-overlay: #18181bcc; + --color-background-overlay: rgb(24 24 27 / 0.8); --color-background-default-dimmed: #27272b; --color-background-default-hover: #27272b; - --color-background-overlay-alt: #18181b66; - --color-background-surface-white: #ffffffe6; - --color-background-overlay-destructive: #f044384d; - --color-background-overlay-backdrop: #18181bf2; - - --color-shadow-shadow-1: #0000000d; - --color-shadow-shadow-3: #0000001a; - --color-shadow-shadow-4: #0000001f; - --color-shadow-shadow-5: #00000029; - --color-shadow-shadow-6: #00000033; - --color-shadow-shadow-7: #0000003d; - --color-shadow-shadow-8: #00000047; - --color-shadow-shadow-9: #0000005c; - --color-shadow-shadow-2: #00000014; - --color-shadow-shadow-10: #00000066; - - --color-workflow-block-border: #ffffff14; - --color-workflow-block-parma-bg: #ffffff0d; + --color-background-overlay-alt: rgb(24 24 27 / 0.4); + --color-background-surface-white: rgb(255 255 255 / 0.9); + --color-background-overlay-destructive: rgb(240 68 56 / 0.3); + --color-background-overlay-backdrop: rgb(24 24 27 / 0.95); + --color-background-body-transparent: rgb(29 29 32 / 0); + + --color-shadow-shadow-1: rgb(0 0 0 / 0.05); + --color-shadow-shadow-3: rgb(0 0 0 / 0.1); + --color-shadow-shadow-4: rgb(0 0 0 / 0.12); + --color-shadow-shadow-5: rgb(0 0 0 / 0.16); + --color-shadow-shadow-6: rgb(0 0 0 / 0.2); + --color-shadow-shadow-7: rgb(0 0 0 / 0.24); + --color-shadow-shadow-8: rgb(0 0 0 / 0.28); + --color-shadow-shadow-9: rgb(0 0 0 / 0.36); + --color-shadow-shadow-2: rgb(0 0 0 / 0.08); + --color-shadow-shadow-10: rgb(0 0 0 / 0.4); + + --color-workflow-block-border: rgb(255 255 255 / 0.08); + --color-workflow-block-parma-bg: rgb(255 255 255 / 0.05); --color-workflow-block-bg: #27272b; - --color-workflow-block-bg-transparent: #27272bf5; - --color-workflow-block-border-highlight: #c8ceda33; + --color-workflow-block-bg-transparent: rgb(39 39 43 / 0.96); + --color-workflow-block-border-highlight: rgb(200 206 218 / 0.2); + --color-workflow-block-wrapper-bg-1: #27272b; + --color-workflow-block-wrapper-bg-2: rgb(39 39 43 / 0.2); - --color-workflow-canvas-workflow-dot-color: #8585ad1c; + --color-workflow-canvas-workflow-dot-color: rgb(133 133 173 / 0.11); --color-workflow-canvas-workflow-bg: #1d1d20; + --color-workflow-canvas-workflow-top-bar-1: #1d1d20; + --color-workflow-canvas-workflow-top-bar-2: rgb(29 29 32 / 0.08); + --color-workflow-canvas-canvas-overlay: rgb(29 29 32 / 0.8); --color-workflow-link-line-active: #5289ff; --color-workflow-link-line-normal: #676f83; --color-workflow-link-line-handle: #5289ff; - --color-workflow-link-line-normal-transparent: #676f8333; + --color-workflow-link-line-normal-transparent: rgb(103 111 131 / 0.2); --color-workflow-link-line-failure-active: #fdb022; --color-workflow-link-line-failure-handle: #fdb022; --color-workflow-link-line-failure-button-bg: #f79009; @@ -450,87 +459,90 @@ html[data-theme="dark"] { --color-workflow-link-line-error-handle: #f97066; --color-workflow-minimap-bg: #27272b; - --color-workflow-minimap-block: #c8ceda14; - - --color-workflow-display-success-bg: #17b26a33; - --color-workflow-display-success-border-1: #17b26ae6; - --color-workflow-display-success-border-2: #17b26acc; - --color-workflow-display-success-vignette-color: #17b26a40; - --color-workflow-display-success-bg-line-pattern: #18181bcc; - - --color-workflow-display-glass-1: #ffffff08; - --color-workflow-display-glass-2: #ffffff0d; - --color-workflow-display-vignette-dark: #00000066; - --color-workflow-display-highlight: #ffffff1f; - --color-workflow-display-outline: #18181bf2; - --color-workflow-display-error-bg: #f0443833; - --color-workflow-display-error-bg-line-pattern: #18181bcc; - --color-workflow-display-error-border-1: #f04438e6; - --color-workflow-display-error-border-2: #f04438cc; - --color-workflow-display-error-vignette-color: #f0443840; - - --color-workflow-display-warning-bg: #f7900933; - --color-workflow-display-warning-bg-line-pattern: #18181bcc; - --color-workflow-display-warning-border-1: #f79009e6; - --color-workflow-display-warning-border-2: #f79009cc; - --color-workflow-display-warning-vignette-color: #f7900940; - - --color-workflow-display-normal-bg: #0ba5ec33; - --color-workflow-display-normal-bg-line-pattern: #18181bcc; - --color-workflow-display-normal-border-1: #0ba5ece6; - --color-workflow-display-normal-border-2: #0ba5eccc; - --color-workflow-display-normal-vignette-color: #0ba5ec40; - - --color-workflow-display-disabled-bg: #c8ceda33; - --color-workflow-display-disabled-bg-line-pattern: #18181bcc; - --color-workflow-display-disabled-border-1: #c8ceda99; - --color-workflow-display-disabled-border-2: #c8ceda40; - --color-workflow-display-disabled-vignette-color: #c8ceda40; - --color-workflow-display-disabled-outline: #18181bf2; - - --color-workflow-workflow-progress-bg-1: #18181b40; - --color-workflow-workflow-progress-bg-2: #18181b0a; - - --color-divider-subtle: #c8ceda14; - --color-divider-regular: #c8ceda24; - --color-divider-deep: #c8ceda33; - --color-divider-burn: #18181bf2; - --color-divider-intense: #c8ceda66; + --color-workflow-minimap-block: rgb(200 206 218 / 0.08); + + --color-workflow-display-success-bg: rgb(23 178 106 / 0.2); + --color-workflow-display-success-border-1: rgb(23 178 106 / 0.9); + --color-workflow-display-success-border-2: rgb(23 178 106 / 0.8); + --color-workflow-display-success-vignette-color: rgb(23 178 106 / 0.25); + --color-workflow-display-success-bg-line-pattern: rgb(24 24 27 / 0.8); + + --color-workflow-display-glass-1: rgb(255 255 255 / 0.03); + --color-workflow-display-glass-2: rgb(255 255 255 / 0.05); + --color-workflow-display-vignette-dark: rgb(0 0 0 / 0.4); + --color-workflow-display-highlight: rgb(255 255 255 / 0.12); + --color-workflow-display-outline: rgb(24 24 27 / 0.95); + --color-workflow-display-error-bg: rgb(240 68 56 / 0.2); + --color-workflow-display-error-bg-line-pattern: rgb(24 24 27 / 0.8); + --color-workflow-display-error-border-1: rgb(240 68 56 / 0.9); + --color-workflow-display-error-border-2: rgb(240 68 56 / 0.8); + --color-workflow-display-error-vignette-color: rgb(240 68 56 / 0.25); + + --color-workflow-display-warning-bg: rgb(247 144 9 / 0.2); + --color-workflow-display-warning-bg-line-pattern: rgb(24 24 27 / 0.8); + --color-workflow-display-warning-border-1: rgb(247 144 9 / 0.9); + --color-workflow-display-warning-border-2: rgb(247 144 9 / 0.8); + --color-workflow-display-warning-vignette-color: rgb(247 144 9 / 0.25); + + --color-workflow-display-normal-bg: rgb(11 165 236 / 0.2); + --color-workflow-display-normal-bg-line-pattern: rgb(24 24 27 / 0.8); + --color-workflow-display-normal-border-1: rgb(11 165 236 / 0.9); + --color-workflow-display-normal-border-2: rgb(11 165 236 / 0.8); + --color-workflow-display-normal-vignette-color: rgb(11 165 236 / 0.25); + + --color-workflow-display-disabled-bg: rgb(200 206 218 / 0.2); + --color-workflow-display-disabled-bg-line-pattern: rgb(24 24 27 / 0.8); + --color-workflow-display-disabled-border-1: rgb(200 206 218 / 0.6); + --color-workflow-display-disabled-border-2: rgb(200 206 218 / 0.25); + --color-workflow-display-disabled-vignette-color: rgb(200 206 218 / 0.25); + --color-workflow-display-disabled-outline: rgb(24 24 27 / 0.95); + + --color-workflow-workflow-progress-bg-1: rgb(24 24 27 / 0.25); + --color-workflow-workflow-progress-bg-2: rgb(24 24 27 / 0.04); + + --color-divider-subtle: rgb(200 206 218 / 0.08); + --color-divider-regular: rgb(200 206 218 / 0.14); + --color-divider-deep: rgb(200 206 218 / 0.2); + --color-divider-burn: rgb(24 24 27 / 0.95); + --color-divider-intense: rgb(200 206 218 / 0.4); --color-divider-solid: #3a3a40; --color-divider-solid-alt: #747481; - --color-state-base-hover: #c8ceda14; - --color-state-base-active: #c8ceda33; - --color-state-base-hover-alt: #c8ceda24; - --color-state-base-handle: #c8ceda4d; - --color-state-base-handle-hover: #c8ceda80; - --color-state-base-hover-subtle: #c8ceda0a; + --color-state-base-hover: rgb(200 206 218 / 0.08); + --color-state-base-active: rgb(200 206 218 / 0.2); + --color-state-base-hover-alt: rgb(200 206 218 / 0.14); + --color-state-base-handle: rgb(200 206 218 / 0.3); + --color-state-base-handle-hover: rgb(200 206 218 / 0.5); + --color-state-base-hover-subtle: rgb(200 206 218 / 0.04); - --color-state-accent-hover: #155aef24; - --color-state-accent-active: #155aef24; - --color-state-accent-hover-alt: #155aef40; + --color-state-accent-hover: rgb(21 90 239 / 0.14); + --color-state-accent-active: rgb(21 90 239 / 0.14); + --color-state-accent-hover-alt: rgb(21 90 239 / 0.25); --color-state-accent-solid: #5289ff; - --color-state-accent-active-alt: #155aef33; + --color-state-accent-active-alt: rgb(21 90 239 / 0.2); - --color-state-destructive-hover: #f0443824; - --color-state-destructive-hover-alt: #f0443840; - --color-state-destructive-active: #f044384d; + --color-state-destructive-hover: rgb(240 68 56 / 0.14); + --color-state-destructive-hover-alt: rgb(240 68 56 / 0.25); + --color-state-destructive-active: rgb(240 68 56 / 0.3); --color-state-destructive-solid: #f97066; --color-state-destructive-border: #f97066; + --color-state-destructive-hover-transparent: rgb(240 68 56 / 0); - --color-state-success-hover: #17b26a24; - --color-state-success-hover-alt: #17b26a40; - --color-state-success-active: #17b26a4d; + --color-state-success-hover: rgb(23 178 106 / 0.14); + --color-state-success-hover-alt: rgb(23 178 106 / 0.25); + --color-state-success-active: rgb(23 178 106 / 0.3); --color-state-success-solid: #47cd89; - --color-state-warning-hover: #f7900924; - --color-state-warning-hover-alt: #f7900940; - --color-state-warning-active: #f790094d; + --color-state-warning-hover: rgb(247 144 9 / 0.14); + --color-state-warning-hover-alt: rgb(247 144 9 / 0.25); + --color-state-warning-active: rgb(247 144 9 / 0.3); --color-state-warning-solid: #f79009; + --color-state-warning-hover-transparent: rgb(247 144 9 / 0); - --color-effects-highlight: #c8ceda14; - --color-effects-highlight-lightmode-off: #c8ceda14; + --color-effects-highlight: rgb(200 206 218 / 0.08); + --color-effects-highlight-lightmode-off: rgb(200 206 218 / 0.08); --color-effects-image-frame: #ffffff; + --color-effects-icon-border: rgb(255 255 255 / 0.15); --color-util-colors-orange-dark-orange-dark-50: #57130a; --color-util-colors-orange-dark-orange-dark-100: #771a0d; @@ -549,7 +561,7 @@ html[data-theme="dark"] { --color-util-colors-orange-orange-500: #ef6820; --color-util-colors-orange-orange-600: #f38744; --color-util-colors-orange-orange-700: #f7b27a; - --color-util-colors-orange-orange-100-transparent: #77291700; + --color-util-colors-orange-orange-100-transparent: rgb(119 41 23 / 0); --color-util-colors-pink-pink-50: #4e0d30; --color-util-colors-pink-pink-100: #851651; @@ -722,21 +734,22 @@ html[data-theme="dark"] { --color-util-colors-midnight-midnight-600: #a7aec5; --color-util-colors-midnight-midnight-700: #c6cbd9; - --color-third-party-Arize: #ffffff; - --color-third-party-Phoenix: #ffffff; --color-third-party-LangChain: #ffffff; --color-third-party-Langfuse: #ffffff; --color-third-party-Github: #ffffff; - --color-third-party-Github-tertiary: #c8ceda99; + --color-third-party-Github-tertiary: rgb(200 206 218 / 0.6); --color-third-party-Github-secondary: #d9d9de; --color-third-party-model-bg-openai: #121212; --color-third-party-model-bg-anthropic: #1d1917; - --color-third-party-model-bg-default: #0b0b0e; + --color-third-party-model-bg-default: #1d1d20; --color-third-party-aws: #141f2e; --color-third-party-aws-alt: #192639; --color-saas-background: #0b0b0e; - --color-saas-pricing-grid-bg: #c8ceda33; + --color-saas-pricing-grid-bg: rgb(200 206 218 / 0.2); + + --color-dify-logo-dify-logo-blue: #e8e8e8; + --color-dify-logo-dify-logo-black: #e8e8e8; } diff --git a/web/themes/light.css b/web/themes/light.css index 97b3b3b4ae..9a0a958bfd 100644 --- a/web/themes/light.css +++ b/web/themes/light.css @@ -1,79 +1,79 @@ /* Attention: Generate by code. Don't update by hand!!! */ html[data-theme="light"] { - --color-components-input-bg-normal: #c8ceda40; + --color-components-input-bg-normal: rgb(200 206 218 / 0.25); --color-components-input-text-placeholder: #98a2b2; - --color-components-input-bg-hover: #c8ceda24; + --color-components-input-bg-hover: rgb(200 206 218 / 0.14); --color-components-input-bg-active: #f9fafb; --color-components-input-border-active: #d0d5dc; --color-components-input-border-destructive: #fda29b; --color-components-input-text-filled: #101828; --color-components-input-bg-destructive: #ffffff; - --color-components-input-bg-disabled: #c8ceda24; + --color-components-input-bg-disabled: rgb(200 206 218 / 0.14); --color-components-input-text-disabled: #d0d5dc; --color-components-input-text-filled-disabled: #676f83; --color-components-input-border-hover: #d0d5dc; --color-components-input-border-active-prompt-1: #0ba5ec; --color-components-input-border-active-prompt-2: #155aef; - --color-components-kbd-bg-gray: #1018280a; - --color-components-kbd-bg-white: #ffffff1f; + --color-components-kbd-bg-gray: rgb(16 24 40 / 0.04); + --color-components-kbd-bg-white: rgb(255 255 255 / 0.12); - --color-components-tooltip-bg: #fffffff2; + --color-components-tooltip-bg: rgb(255 255 255 / 0.95); --color-components-button-primary-text: #ffffff; --color-components-button-primary-bg: #155aef; - --color-components-button-primary-border: #1018280a; + --color-components-button-primary-border: rgb(16 24 40 / 0.04); --color-components-button-primary-bg-hover: #004aeb; - --color-components-button-primary-border-hover: #10182814; - --color-components-button-primary-bg-disabled: #155aef24; - --color-components-button-primary-border-disabled: #ffffff00; - --color-components-button-primary-text-disabled: #ffffff99; + --color-components-button-primary-border-hover: rgb(16 24 40 / 0.08); + --color-components-button-primary-bg-disabled: rgb(21 90 239 / 0.14); + --color-components-button-primary-border-disabled: rgb(255 255 255 / 0); + --color-components-button-primary-text-disabled: rgb(255 255 255 / 0.6); --color-components-button-secondary-text: #354052; - --color-components-button-secondary-text-disabled: #10182840; + --color-components-button-secondary-text-disabled: rgb(16 24 40 / 0.25); --color-components-button-secondary-bg: #ffffff; --color-components-button-secondary-bg-hover: #f9fafb; --color-components-button-secondary-bg-disabled: #f9fafb; - --color-components-button-secondary-border: #10182824; - --color-components-button-secondary-border-hover: #10182833; - --color-components-button-secondary-border-disabled: #1018280a; + --color-components-button-secondary-border: rgb(16 24 40 / 0.14); + --color-components-button-secondary-border-hover: rgb(16 24 40 / 0.2); + --color-components-button-secondary-border-disabled: rgb(16 24 40 / 0.04); --color-components-button-tertiary-text: #354052; - --color-components-button-tertiary-text-disabled: #10182840; + --color-components-button-tertiary-text-disabled: rgb(16 24 40 / 0.25); --color-components-button-tertiary-bg: #f2f4f7; --color-components-button-tertiary-bg-hover: #e9ebf0; --color-components-button-tertiary-bg-disabled: #f9fafb; --color-components-button-ghost-text: #354052; - --color-components-button-ghost-text-disabled: #10182840; - --color-components-button-ghost-bg-hover: #c8ceda33; + --color-components-button-ghost-text-disabled: rgb(16 24 40 / 0.25); + --color-components-button-ghost-bg-hover: rgb(200 206 218 / 0.2); --color-components-button-destructive-primary-text: #ffffff; - --color-components-button-destructive-primary-text-disabled: #ffffff99; + --color-components-button-destructive-primary-text-disabled: rgb(255 255 255 / 0.6); --color-components-button-destructive-primary-bg: #d92d20; --color-components-button-destructive-primary-bg-hover: #b42318; --color-components-button-destructive-primary-bg-disabled: #fee4e2; - --color-components-button-destructive-primary-border: #18181b0a; - --color-components-button-destructive-primary-border-hover: #18181b14; - --color-components-button-destructive-primary-border-disabled: #ffffff00; + --color-components-button-destructive-primary-border: rgb(24 24 27 / 0.04); + --color-components-button-destructive-primary-border-hover: rgb(24 24 27 / 0.08); + --color-components-button-destructive-primary-border-disabled: rgb(255 255 255 / 0); --color-components-button-destructive-secondary-text: #d92d20; - --color-components-button-destructive-secondary-text-disabled: #f0443833; + --color-components-button-destructive-secondary-text-disabled: rgb(240 68 56 / 0.2); --color-components-button-destructive-secondary-bg: #ffffff; --color-components-button-destructive-secondary-bg-hover: #fef3f2; --color-components-button-destructive-secondary-bg-disabled: #fef3f2; - --color-components-button-destructive-secondary-border: #18181b14; - --color-components-button-destructive-secondary-border-hover: #f0443840; - --color-components-button-destructive-secondary-border-disabled: #f044380a; + --color-components-button-destructive-secondary-border: rgb(24 24 27 / 0.08); + --color-components-button-destructive-secondary-border-hover: rgb(240 68 56 / 0.25); + --color-components-button-destructive-secondary-border-disabled: rgb(240 68 56 / 0.04); --color-components-button-destructive-tertiary-text: #d92d20; - --color-components-button-destructive-tertiary-text-disabled: #f0443833; + --color-components-button-destructive-tertiary-text-disabled: rgb(240 68 56 / 0.2); --color-components-button-destructive-tertiary-bg: #fee4e2; --color-components-button-destructive-tertiary-bg-hover: #fecdca; - --color-components-button-destructive-tertiary-bg-disabled: #f044380a; + --color-components-button-destructive-tertiary-bg-disabled: rgb(240 68 56 / 0.04); --color-components-button-destructive-ghost-text: #d92d20; - --color-components-button-destructive-ghost-text-disabled: #f0443833; + --color-components-button-destructive-ghost-text-disabled: rgb(240 68 56 / 0.2); --color-components-button-destructive-ghost-bg-hover: #fee4e2; --color-components-button-secondary-accent-text: #155aef; @@ -81,22 +81,22 @@ html[data-theme="light"] { --color-components-button-secondary-accent-bg: #ffffff; --color-components-button-secondary-accent-bg-hover: #f2f4f7; --color-components-button-secondary-accent-bg-disabled: #f9fafb; - --color-components-button-secondary-accent-border: #10182824; - --color-components-button-secondary-accent-border-hover: #10182824; - --color-components-button-secondary-accent-border-disabled: #1018280a; + --color-components-button-secondary-accent-border: rgb(16 24 40 / 0.14); + --color-components-button-secondary-accent-border-hover: rgb(16 24 40 / 0.14); + --color-components-button-secondary-accent-border-disabled: rgb(16 24 40 / 0.04); --color-components-button-indigo-bg: #444ce7; --color-components-button-indigo-bg-hover: #3538cd; - --color-components-button-indigo-bg-disabled: #6172f324; + --color-components-button-indigo-bg-disabled: rgb(97 114 243 / 0.14); --color-components-checkbox-icon: #ffffff; - --color-components-checkbox-icon-disabled: #ffffff80; + --color-components-checkbox-icon-disabled: rgb(255 255 255 / 0.5); --color-components-checkbox-bg: #155aef; --color-components-checkbox-bg-hover: #004aeb; --color-components-checkbox-bg-disabled: #f2f4f7; --color-components-checkbox-border: #d0d5dc; --color-components-checkbox-border-hover: #98a2b2; - --color-components-checkbox-border-disabled: #18181b0a; + --color-components-checkbox-border-disabled: rgb(24 24 27 / 0.04); --color-components-checkbox-bg-unchecked: #ffffff; --color-components-checkbox-bg-unchecked-hover: #ffffff; --color-components-checkbox-bg-disabled-checked: #b2caff; @@ -104,15 +104,15 @@ html[data-theme="light"] { --color-components-radio-border-checked: #155aef; --color-components-radio-border-checked-hover: #004aeb; --color-components-radio-border-checked-disabled: #b2caff; - --color-components-radio-bg-disabled: #ffffff00; + --color-components-radio-bg-disabled: rgb(255 255 255 / 0); --color-components-radio-border: #d0d5dc; --color-components-radio-border-hover: #98a2b2; - --color-components-radio-border-disabled: #18181b0a; - --color-components-radio-bg: #ffffff00; - --color-components-radio-bg-hover: #ffffff00; + --color-components-radio-border-disabled: rgb(24 24 27 / 0.04); + --color-components-radio-bg: rgb(255 255 255 / 0); + --color-components-radio-bg-hover: rgb(255 255 255 / 0); --color-components-toggle-knob: #ffffff; - --color-components-toggle-knob-disabled: #fffffff2; + --color-components-toggle-knob-disabled: rgb(255 255 255 / 0.95); --color-components-toggle-bg: #155aef; --color-components-toggle-bg-hover: #004aeb; --color-components-toggle-bg-disabled: #d1e0ff; @@ -124,48 +124,52 @@ html[data-theme="light"] { --color-components-card-bg: #fcfcfd; --color-components-card-border: #ffffff; --color-components-card-bg-alt: #ffffff; + --color-components-card-bg-transparent: rgb(252 252 253 / 0); + --color-components-card-bg-alt-transparent: rgb(255 255 255 / 0); --color-components-menu-item-text: #495464; --color-components-menu-item-text-active: #18222f; --color-components-menu-item-text-hover: #354052; --color-components-menu-item-text-active-accent: #18222f; + --color-components-menu-item-bg-active: rgb(21 90 239 / 0.08); + --color-components-menu-item-bg-hover: rgb(200 206 218 / 0.2); --color-components-panel-bg: #ffffff; - --color-components-panel-bg-blur: #fffffff2; - --color-components-panel-border: #10182814; - --color-components-panel-border-subtle: #10182814; + --color-components-panel-bg-blur: rgb(255 255 255 / 0.95); + --color-components-panel-border: rgb(16 24 40 / 0.08); + --color-components-panel-border-subtle: rgb(16 24 40 / 0.08); --color-components-panel-gradient-2: #f9fafb; --color-components-panel-gradient-1: #ffffff; --color-components-panel-bg-alt: #f9fafb; --color-components-panel-on-panel-item-bg: #ffffff; --color-components-panel-on-panel-item-bg-hover: #f9fafb; --color-components-panel-on-panel-item-bg-alt: #f9fafb; - --color-components-panel-on-panel-item-bg-transparent: #fffffff2; - --color-components-panel-on-panel-item-bg-hover-transparent: #f9fafb00; - --color-components-panel-on-panel-item-bg-destructive-hover-transparent: #fef3f200; + --color-components-panel-on-panel-item-bg-transparent: rgb(255 255 255 / 0.95); + --color-components-panel-on-panel-item-bg-hover-transparent: rgb(249 250 251 / 0); + --color-components-panel-on-panel-item-bg-destructive-hover-transparent: rgb(254 243 242 / 0); - --color-components-panel-bg-transparent: #ffffff00; + --color-components-panel-bg-transparent: rgb(255 255 255 / 0); --color-components-main-nav-nav-button-text: #495464; --color-components-main-nav-nav-button-text-active: #155aef; - --color-components-main-nav-nav-button-bg: #ffffff00; + --color-components-main-nav-nav-button-bg: rgb(255 255 255 / 0); --color-components-main-nav-nav-button-bg-active: #fcfcfd; - --color-components-main-nav-nav-button-border: #fffffff2; - --color-components-main-nav-nav-button-bg-hover: #1018280a; + --color-components-main-nav-nav-button-border: rgb(255 255 255 / 0.95); + --color-components-main-nav-nav-button-bg-hover: rgb(16 24 40 / 0.04); --color-components-main-nav-nav-user-border: #ffffff; --color-components-slider-knob: #ffffff; --color-components-slider-knob-hover: #ffffff; - --color-components-slider-knob-disabled: #fffffff2; + --color-components-slider-knob-disabled: rgb(255 255 255 / 0.95); --color-components-slider-range: #296dff; --color-components-slider-track: #e9ebf0; - --color-components-slider-knob-border-hover: #10182833; - --color-components-slider-knob-border: #10182824; + --color-components-slider-knob-border-hover: rgb(16 24 40 / 0.2); + --color-components-slider-knob-border: rgb(16 24 40 / 0.14); --color-components-segmented-control-item-active-bg: #ffffff; --color-components-segmented-control-item-active-border: #ffffff; - --color-components-segmented-control-bg-normal: #c8ceda33; + --color-components-segmented-control-bg-normal: rgb(200 206 218 / 0.2); --color-components-segmented-control-item-active-accent-bg: #ffffff; --color-components-segmented-control-item-active-accent-border: #ffffff; @@ -181,94 +185,94 @@ html[data-theme="light"] { --color-components-badge-white-to-dark: #ffffff; --color-components-badge-status-light-success-bg: #47cd89; --color-components-badge-status-light-success-border-inner: #17b26a; - --color-components-badge-status-light-success-halo: #17b26a40; + --color-components-badge-status-light-success-halo: rgb(23 178 106 / 0.25); --color-components-badge-status-light-border-outer: #ffffff; - --color-components-badge-status-light-high-light: #ffffff4d; + --color-components-badge-status-light-high-light: rgb(255 255 255 / 0.3); --color-components-badge-status-light-warning-bg: #fdb022; --color-components-badge-status-light-warning-border-inner: #f79009; - --color-components-badge-status-light-warning-halo: #f7900940; + --color-components-badge-status-light-warning-halo: rgb(247 144 9 / 0.25); --color-components-badge-status-light-error-bg: #f97066; --color-components-badge-status-light-error-border-inner: #f04438; - --color-components-badge-status-light-error-halo: #f0443840; + --color-components-badge-status-light-error-halo: rgb(240 68 56 / 0.25); --color-components-badge-status-light-normal-bg: #36bffa; --color-components-badge-status-light-normal-border-inner: #0ba5ec; - --color-components-badge-status-light-normal-halo: #0ba5ec40; + --color-components-badge-status-light-normal-halo: rgb(11 165 236 / 0.25); --color-components-badge-status-light-disabled-bg: #98a2b2; --color-components-badge-status-light-disabled-border-inner: #676f83; - --color-components-badge-status-light-disabled-halo: #1018280a; + --color-components-badge-status-light-disabled-halo: rgb(16 24 40 / 0.04); - --color-components-badge-bg-green-soft: #17b26a14; - --color-components-badge-bg-orange-soft: #f7900914; - --color-components-badge-bg-red-soft: #f0443814; - --color-components-badge-bg-blue-light-soft: #0ba5ec14; - --color-components-badge-bg-gray-soft: #1018280a; - --color-components-badge-bg-dimm: #ffffff0d; + --color-components-badge-bg-green-soft: rgb(23 178 106 / 0.08); + --color-components-badge-bg-orange-soft: rgb(247 144 9 / 0.08); + --color-components-badge-bg-red-soft: rgb(240 68 56 / 0.08); + --color-components-badge-bg-blue-light-soft: rgb(11 165 236 / 0.08); + --color-components-badge-bg-gray-soft: rgb(16 24 40 / 0.04); + --color-components-badge-bg-dimm: rgb(255 255 255 / 0.05); --color-components-chart-line: #296dff; - --color-components-chart-area-1: #155aef24; - --color-components-chart-area-2: #155aef0a; + --color-components-chart-area-1: rgb(21 90 239 / 0.14); + --color-components-chart-area-2: rgb(21 90 239 / 0.04); --color-components-chart-current-1: #155aef; --color-components-chart-current-2: #d1e0ff; --color-components-chart-bg: #ffffff; - --color-components-actionbar-bg: #fffffff2; - --color-components-actionbar-border: #1018280a; + --color-components-actionbar-bg: rgb(255 255 255 / 0.95); + --color-components-actionbar-border: rgb(16 24 40 / 0.04); --color-components-actionbar-bg-accent: #f5f7ff; --color-components-actionbar-border-accent: #b2caff; --color-components-dropzone-bg-alt: #f2f4f7; --color-components-dropzone-bg: #f9fafb; - --color-components-dropzone-bg-accent: #155aef24; - --color-components-dropzone-border: #10182814; - --color-components-dropzone-border-alt: #10182833; + --color-components-dropzone-bg-accent: rgb(21 90 239 / 0.14); + --color-components-dropzone-border: rgb(16 24 40 / 0.08); + --color-components-dropzone-border-alt: rgb(16 24 40 / 0.2); --color-components-dropzone-border-accent: #84abff; --color-components-progress-brand-progress: #296dff; --color-components-progress-brand-border: #296dff; - --color-components-progress-brand-bg: #155aef0a; + --color-components-progress-brand-bg: rgb(21 90 239 / 0.04); --color-components-progress-white-progress: #ffffff; - --color-components-progress-white-border: #fffffff2; - --color-components-progress-white-bg: #ffffff03; + --color-components-progress-white-border: rgb(255 255 255 / 0.95); + --color-components-progress-white-bg: rgb(255 255 255 / 0.01); --color-components-progress-gray-progress: #98a2b2; --color-components-progress-gray-border: #98a2b2; - --color-components-progress-gray-bg: #c8ceda05; + --color-components-progress-gray-bg: rgb(200 206 218 / 0.02); --color-components-progress-warning-progress: #f79009; --color-components-progress-warning-border: #f79009; - --color-components-progress-warning-bg: #f790090a; + --color-components-progress-warning-bg: rgb(247 144 9 / 0.04); --color-components-progress-error-progress: #f04438; --color-components-progress-error-border: #f04438; - --color-components-progress-error-bg: #f044380a; + --color-components-progress-error-bg: rgb(240 68 56 / 0.04); --color-components-chat-input-audio-bg: #eff4ff; - --color-components-chat-input-audio-wave-default: #155aef33; - --color-components-chat-input-bg-mask-1: #ffffff03; + --color-components-chat-input-audio-wave-default: rgb(21 90 239 / 0.2); + --color-components-chat-input-bg-mask-1: rgb(255 255 255 / 0.01); --color-components-chat-input-bg-mask-2: #f2f4f7; --color-components-chat-input-border: #ffffff; --color-components-chat-input-audio-wave-active: #296dff; --color-components-chat-input-audio-bg-alt: #fcfcfd; --color-components-avatar-shape-fill-stop-0: #ffffff; - --color-components-avatar-shape-fill-stop-100: #ffffffe6; + --color-components-avatar-shape-fill-stop-100: rgb(255 255 255 / 0.9); - --color-components-avatar-bg-mask-stop-0: #ffffff1f; - --color-components-avatar-bg-mask-stop-100: #ffffff14; + --color-components-avatar-bg-mask-stop-0: rgb(255 255 255 / 0.12); + --color-components-avatar-bg-mask-stop-100: rgb(255 255 255 / 0.08); --color-components-avatar-default-avatar-bg: #d0d5dc; - --color-components-avatar-mask-darkmode-dimmed: #ffffff00; + --color-components-avatar-mask-darkmode-dimmed: rgb(255 255 255 / 0); --color-components-label-gray: #f2f4f7; --color-components-premium-badge-blue-bg-stop-0: #5289ff; --color-components-premium-badge-blue-bg-stop-100: #155aef; - --color-components-premium-badge-blue-stroke-stop-0: #fffffff2; + --color-components-premium-badge-blue-stroke-stop-0: rgb(255 255 255 / 0.95); --color-components-premium-badge-blue-stroke-stop-100: #155aef; --color-components-premium-badge-blue-text-stop-0: #f5f7ff; --color-components-premium-badge-blue-text-stop-100: #d1e0ff; @@ -276,14 +280,14 @@ html[data-theme="light"] { --color-components-premium-badge-blue-bg-stop-0-hover: #296dff; --color-components-premium-badge-blue-bg-stop-100-hover: #004aeb; --color-components-premium-badge-blue-glow-hover: #84abff; - --color-components-premium-badge-blue-stroke-stop-0-hover: #fffffff2; + --color-components-premium-badge-blue-stroke-stop-0-hover: rgb(255 255 255 / 0.95); --color-components-premium-badge-blue-stroke-stop-100-hover: #00329e; - --color-components-premium-badge-highlight-stop-0: #ffffff1f; - --color-components-premium-badge-highlight-stop-100: #ffffff4d; + --color-components-premium-badge-highlight-stop-0: rgb(255 255 255 / 0.12); + --color-components-premium-badge-highlight-stop-100: rgb(255 255 255 / 0.3); --color-components-premium-badge-indigo-bg-stop-0: #8098f9; --color-components-premium-badge-indigo-bg-stop-100: #444ce7; - --color-components-premium-badge-indigo-stroke-stop-0: #fffffff2; + --color-components-premium-badge-indigo-stroke-stop-0: rgb(255 255 255 / 0.95); --color-components-premium-badge-indigo-stroke-stop-100: #6172f3; --color-components-premium-badge-indigo-text-stop-0: #f5f8ff; --color-components-premium-badge-indigo-text-stop-100: #e0eaff; @@ -291,12 +295,12 @@ html[data-theme="light"] { --color-components-premium-badge-indigo-glow-hover: #a4bcfd; --color-components-premium-badge-indigo-bg-stop-0-hover: #6172f3; --color-components-premium-badge-indigo-bg-stop-100-hover: #2d31a6; - --color-components-premium-badge-indigo-stroke-stop-0-hover: #fffffff2; + --color-components-premium-badge-indigo-stroke-stop-0-hover: rgb(255 255 255 / 0.95); --color-components-premium-badge-indigo-stroke-stop-100-hover: #2d31a6; --color-components-premium-badge-grey-bg-stop-0: #98a2b2; --color-components-premium-badge-grey-bg-stop-100: #676f83; - --color-components-premium-badge-grey-stroke-stop-0: #fffffff2; + --color-components-premium-badge-grey-stroke-stop-0: rgb(255 255 255 / 0.95); --color-components-premium-badge-grey-stroke-stop-100: #676f83; --color-components-premium-badge-grey-text-stop-0: #fcfcfd; --color-components-premium-badge-grey-text-stop-100: #f2f4f7; @@ -304,12 +308,12 @@ html[data-theme="light"] { --color-components-premium-badge-grey-glow-hover: #d0d5dc; --color-components-premium-badge-grey-bg-stop-0-hover: #676f83; --color-components-premium-badge-grey-bg-stop-100-hover: #354052; - --color-components-premium-badge-grey-stroke-stop-0-hover: #fffffff2; + --color-components-premium-badge-grey-stroke-stop-0-hover: rgb(255 255 255 / 0.95); --color-components-premium-badge-grey-stroke-stop-100-hover: #354052; --color-components-premium-badge-orange-bg-stop-0: #ff692e; --color-components-premium-badge-orange-bg-stop-100: #e04f16; - --color-components-premium-badge-orange-stroke-stop-0: #fffffff2; + --color-components-premium-badge-orange-stroke-stop-0: rgb(255 255 255 / 0.95); --color-components-premium-badge-orange-stroke-stop-100: #e62e05; --color-components-premium-badge-orange-text-stop-0: #fefaf5; --color-components-premium-badge-orange-text-stop-100: #fdead7; @@ -317,14 +321,14 @@ html[data-theme="light"] { --color-components-premium-badge-orange-glow-hover: #f7b27a; --color-components-premium-badge-orange-bg-stop-0-hover: #ff4405; --color-components-premium-badge-orange-bg-stop-100-hover: #b93815; - --color-components-premium-badge-orange-stroke-stop-0-hover: #fffffff2; + --color-components-premium-badge-orange-stroke-stop-0-hover: rgb(255 255 255 / 0.95); --color-components-premium-badge-orange-stroke-stop-100-hover: #bc1b06; - --color-components-progress-bar-bg: #155aef0a; - --color-components-progress-bar-progress: #155aef24; - --color-components-progress-bar-border: #1018280a; + --color-components-progress-bar-bg: rgb(21 90 239 / 0.04); + --color-components-progress-bar-progress: rgb(21 90 239 / 0.14); + --color-components-progress-bar-border: rgb(16 24 40 / 0.04); --color-components-progress-bar-progress-solid: #296dff; - --color-components-progress-bar-progress-highlight: #155aef33; + --color-components-progress-bar-progress-highlight: rgb(21 90 239 / 0.2); --color-components-icon-bg-red-solid: #d92d20; --color-components-icon-bg-rose-solid: #e31b54; @@ -356,7 +360,7 @@ html[data-theme="light"] { --color-text-primary: #101828; --color-text-secondary: #354052; --color-text-tertiary: #676f83; - --color-text-quaternary: #1018284d; + --color-text-quaternary: rgb(16 24 40 / 0.3); --color-text-destructive: #d92d20; --color-text-success: #079455; --color-text-warning: #dc6803; @@ -369,75 +373,80 @@ html[data-theme="light"] { --color-text-disabled: #d0d5dc; --color-text-accent-secondary: #296dff; --color-text-accent-light-mode-only: #155aef; - --color-text-text-selected: #155aef24; - --color-text-secondary-on-surface: #ffffffe6; + --color-text-text-selected: rgb(21 90 239 / 0.14); + --color-text-secondary-on-surface: rgb(255 255 255 / 0.9); --color-text-logo-text: #18222f; --color-text-empty-state-icon: #d0d5dc; --color-text-inverted: #000000; - --color-text-inverted-dimmed: #000000f2; + --color-text-inverted-dimmed: rgb(0 0 0 / 0.95); --color-background-body: #f2f4f7; --color-background-default-subtle: #fcfcfd; --color-background-neutral-subtle: #f9fafb; - --color-background-sidenav-bg: #ffffffcc; + --color-background-sidenav-bg: rgb(255 255 255 / 0.8); --color-background-default: #ffffff; --color-background-soft: #f9fafb; --color-background-gradient-bg-fill-chat-bg-1: #f9fafb; --color-background-gradient-bg-fill-chat-bg-2: #f2f4f7; --color-background-gradient-bg-fill-chat-bubble-bg-1: #ffffff; - --color-background-gradient-bg-fill-chat-bubble-bg-2: #ffffff99; - --color-background-gradient-bg-fill-chat-bubble-bg-3: #e1effe; - --color-background-gradient-bg-fill-debug-bg-1: #ffffff00; - --color-background-gradient-bg-fill-debug-bg-2: #c8ceda24; - - --color-background-gradient-mask-gray: #c8ceda33; - --color-background-gradient-mask-transparent: #ffffff00; - --color-background-gradient-mask-input-clear-2: #e9ebf000; + --color-background-gradient-bg-fill-chat-bubble-bg-2: rgb(255 255 255 / 0.6); + --color-background-gradient-bg-fill-debug-bg-1: rgb(255 255 255 / 0); + --color-background-gradient-bg-fill-debug-bg-2: rgb(200 206 218 / 0.14); + + --color-background-gradient-mask-gray: rgb(200 206 218 / 0.2); + --color-background-gradient-mask-transparent: rgb(255 255 255 / 0); + --color-background-gradient-mask-input-clear-2: rgb(233 235 240 / 0); --color-background-gradient-mask-input-clear-1: #e9ebf0; - --color-background-gradient-mask-transparent-dark: #00000000; - --color-background-gradient-mask-side-panel-2: #1018284d; - --color-background-gradient-mask-side-panel-1: #10182805; + --color-background-gradient-mask-transparent-dark: rgb(0 0 0 / 0); + --color-background-gradient-mask-side-panel-2: rgb(16 24 40 / 0.3); + --color-background-gradient-mask-side-panel-1: rgb(16 24 40 / 0.02); --color-background-default-burn: #e9ebf0; - --color-background-overlay-fullscreen: #f9fafbf2; - --color-background-default-lighter: #ffffff80; + --color-background-overlay-fullscreen: rgb(249 250 251 / 0.95); + --color-background-default-lighter: rgb(255 255 255 / 0.5); --color-background-section: #f9fafb; - --color-background-interaction-from-bg-1: #c8ceda33; - --color-background-interaction-from-bg-2: #c8ceda24; + --color-background-interaction-from-bg-1: rgb(200 206 218 / 0.2); + --color-background-interaction-from-bg-2: rgb(200 206 218 / 0.14); --color-background-section-burn: #f2f4f7; --color-background-default-dodge: #ffffff; - --color-background-overlay: #10182899; + --color-background-overlay: rgb(16 24 40 / 0.6); --color-background-default-dimmed: #e9ebf0; --color-background-default-hover: #f9fafb; - --color-background-overlay-alt: #10182866; - --color-background-surface-white: #fffffff2; - --color-background-overlay-destructive: #f044384d; - --color-background-overlay-backdrop: #f2f4f7f2; - - --color-shadow-shadow-1: #09090b08; - --color-shadow-shadow-3: #09090b0d; - --color-shadow-shadow-4: #09090b0f; - --color-shadow-shadow-5: #09090b14; - --color-shadow-shadow-6: #09090b1a; - --color-shadow-shadow-7: #09090b1f; - --color-shadow-shadow-8: #09090b24; - --color-shadow-shadow-9: #09090b2e; - --color-shadow-shadow-2: #09090b0a; - --color-shadow-shadow-10: #09090b0d; + --color-background-overlay-alt: rgb(16 24 40 / 0.4); + --color-background-surface-white: rgb(255 255 255 / 0.95); + --color-background-overlay-destructive: rgb(240 68 56 / 0.3); + --color-background-overlay-backdrop: rgb(242 244 247 / 0.95); + --color-background-body-transparent: rgb(242 244 247 / 0); + + --color-shadow-shadow-1: rgb(9 9 11 / 0.03); + --color-shadow-shadow-3: rgb(9 9 11 / 0.05); + --color-shadow-shadow-4: rgb(9 9 11 / 0.06); + --color-shadow-shadow-5: rgb(9 9 11 / 0.08); + --color-shadow-shadow-6: rgb(9 9 11 / 0.1); + --color-shadow-shadow-7: rgb(9 9 11 / 0.12); + --color-shadow-shadow-8: rgb(9 9 11 / 0.14); + --color-shadow-shadow-9: rgb(9 9 11 / 0.18); + --color-shadow-shadow-2: rgb(9 9 11 / 0.04); + --color-shadow-shadow-10: rgb(9 9 11 / 0.05); --color-workflow-block-border: #ffffff; --color-workflow-block-parma-bg: #f2f4f7; --color-workflow-block-bg: #fcfcfd; - --color-workflow-block-bg-transparent: #fcfcfde6; - --color-workflow-block-border-highlight: #155aef24; + --color-workflow-block-bg-transparent: rgb(252 252 253 / 0.9); + --color-workflow-block-border-highlight: rgb(21 90 239 / 0.14); + --color-workflow-block-wrapper-bg-1: #e9ebf0; + --color-workflow-block-wrapper-bg-2: rgb(233 235 240 / 0.2); - --color-workflow-canvas-workflow-dot-color: #8585ad26; + --color-workflow-canvas-workflow-dot-color: rgb(133 133 173 / 0.15); --color-workflow-canvas-workflow-bg: #f2f4f7; + --color-workflow-canvas-workflow-top-bar-1: #f2f4f7; + --color-workflow-canvas-workflow-top-bar-2: rgb(242 244 247 / 0.24); + --color-workflow-canvas-canvas-overlay: rgb(242 244 247 / 0.8); --color-workflow-link-line-active: #296dff; --color-workflow-link-line-normal: #d0d5dc; --color-workflow-link-line-handle: #296dff; - --color-workflow-link-line-normal-transparent: #d0d5dc33; + --color-workflow-link-line-normal-transparent: rgb(208 213 220 / 0.2); --color-workflow-link-line-failure-active: #f79009; --color-workflow-link-line-failure-handle: #f79009; --color-workflow-link-line-failure-button-bg: #dc6803; @@ -450,73 +459,74 @@ html[data-theme="light"] { --color-workflow-link-line-error-handle: #f04438; --color-workflow-minimap-bg: #e9ebf0; - --color-workflow-minimap-block: #c8ceda4d; + --color-workflow-minimap-block: rgb(200 206 218 / 0.3); --color-workflow-display-success-bg: #ecfdf3; - --color-workflow-display-success-border-1: #17b26acc; - --color-workflow-display-success-border-2: #17b26a80; - --color-workflow-display-success-vignette-color: #17b26a33; - --color-workflow-display-success-bg-line-pattern: #17b26a4d; - - --color-workflow-display-glass-1: #ffffff1f; - --color-workflow-display-glass-2: #ffffff80; - --color-workflow-display-vignette-dark: #0000001f; - --color-workflow-display-highlight: #ffffff80; - --color-workflow-display-outline: #0000000d; + --color-workflow-display-success-border-1: rgb(23 178 106 / 0.8); + --color-workflow-display-success-border-2: rgb(23 178 106 / 0.5); + --color-workflow-display-success-vignette-color: rgb(23 178 106 / 0.2); + --color-workflow-display-success-bg-line-pattern: rgb(23 178 106 / 0.3); + + --color-workflow-display-glass-1: rgb(255 255 255 / 0.12); + --color-workflow-display-glass-2: rgb(255 255 255 / 0.5); + --color-workflow-display-vignette-dark: rgb(0 0 0 / 0.12); + --color-workflow-display-highlight: rgb(255 255 255 / 0.5); + --color-workflow-display-outline: rgb(0 0 0 / 0.05); --color-workflow-display-error-bg: #fef3f2; - --color-workflow-display-error-bg-line-pattern: #f044384d; - --color-workflow-display-error-border-1: #f04438cc; - --color-workflow-display-error-border-2: #f0443880; - --color-workflow-display-error-vignette-color: #f0443833; + --color-workflow-display-error-bg-line-pattern: rgb(240 68 56 / 0.3); + --color-workflow-display-error-border-1: rgb(240 68 56 / 0.8); + --color-workflow-display-error-border-2: rgb(240 68 56 / 0.5); + --color-workflow-display-error-vignette-color: rgb(240 68 56 / 0.2); --color-workflow-display-warning-bg: #fffaeb; - --color-workflow-display-warning-bg-line-pattern: #f790094d; - --color-workflow-display-warning-border-1: #f79009cc; - --color-workflow-display-warning-border-2: #f7900980; - --color-workflow-display-warning-vignette-color: #f7900933; + --color-workflow-display-warning-bg-line-pattern: rgb(247 144 9 / 0.3); + --color-workflow-display-warning-border-1: rgb(247 144 9 / 0.8); + --color-workflow-display-warning-border-2: rgb(247 144 9 / 0.5); + --color-workflow-display-warning-vignette-color: rgb(247 144 9 / 0.2); --color-workflow-display-normal-bg: #f0f9ff; - --color-workflow-display-normal-bg-line-pattern: #0ba5ec4d; - --color-workflow-display-normal-border-1: #0ba5eccc; - --color-workflow-display-normal-border-2: #0ba5ec80; - --color-workflow-display-normal-vignette-color: #0ba5ec33; + --color-workflow-display-normal-bg-line-pattern: rgb(11 165 236 / 0.3); + --color-workflow-display-normal-border-1: rgb(11 165 236 / 0.8); + --color-workflow-display-normal-border-2: rgb(11 165 236 / 0.5); + --color-workflow-display-normal-vignette-color: rgb(11 165 236 / 0.2); --color-workflow-display-disabled-bg: #f9fafb; - --color-workflow-display-disabled-bg-line-pattern: #c8ceda4d; - --color-workflow-display-disabled-border-1: #c8ceda99; - --color-workflow-display-disabled-border-2: #c8ceda66; - --color-workflow-display-disabled-vignette-color: #c8ceda66; - --color-workflow-display-disabled-outline: #00000000; - - --color-workflow-workflow-progress-bg-1: #c8ceda33; - --color-workflow-workflow-progress-bg-2: #c8ceda0a; - - --color-divider-subtle: #1018280a; - --color-divider-regular: #10182814; - --color-divider-deep: #10182824; - --color-divider-burn: #1018280a; - --color-divider-intense: #1018284d; + --color-workflow-display-disabled-bg-line-pattern: rgb(200 206 218 / 0.3); + --color-workflow-display-disabled-border-1: rgb(200 206 218 / 0.6); + --color-workflow-display-disabled-border-2: rgb(200 206 218 / 0.4); + --color-workflow-display-disabled-vignette-color: rgb(200 206 218 / 0.4); + --color-workflow-display-disabled-outline: rgb(0 0 0 / 0); + + --color-workflow-workflow-progress-bg-1: rgb(200 206 218 / 0.2); + --color-workflow-workflow-progress-bg-2: rgb(200 206 218 / 0.04); + + --color-divider-subtle: rgb(16 24 40 / 0.04); + --color-divider-regular: rgb(16 24 40 / 0.08); + --color-divider-deep: rgb(16 24 40 / 0.14); + --color-divider-burn: rgb(16 24 40 / 0.04); + --color-divider-intense: rgb(16 24 40 / 0.3); --color-divider-solid: #d0d5dc; --color-divider-solid-alt: #98a2b2; - --color-state-base-hover: #c8ceda33; - --color-state-base-active: #c8ceda66; - --color-state-base-hover-alt: #c8ceda66; - --color-state-base-handle: #10182833; - --color-state-base-handle-hover: #1018284d; - --color-state-base-hover-subtle: #c8ceda14; + --color-state-base-hover: rgb(200 206 218 / 0.2); + --color-state-base-active: rgb(200 206 218 / 0.4); + --color-state-base-hover-alt: rgb(200 206 218 / 0.4); + --color-state-base-handle: rgb(16 24 40 / 0.2); + --color-state-base-handle-hover: rgb(16 24 40 / 0.3); + --color-state-base-hover-subtle: rgb(200 206 218 / 0.08); --color-state-accent-hover: #eff4ff; - --color-state-accent-active: #155aef14; + --color-state-accent-active: rgb(21 90 239 / 0.08); --color-state-accent-hover-alt: #d1e0ff; --color-state-accent-solid: #296dff; - --color-state-accent-active-alt: #155aef24; + --color-state-accent-active-alt: rgb(21 90 239 / 0.14); --color-state-destructive-hover: #fef3f2; --color-state-destructive-hover-alt: #fee4e2; --color-state-destructive-active: #fecdca; --color-state-destructive-solid: #f04438; --color-state-destructive-border: #fda29b; + --color-state-destructive-hover-transparent: rgb(254 243 242 / 0); --color-state-success-hover: #ecfdf3; --color-state-success-hover-alt: #dcfae6; @@ -527,10 +537,12 @@ html[data-theme="light"] { --color-state-warning-hover-alt: #fef0c7; --color-state-warning-active: #fedf89; --color-state-warning-solid: #f79009; + --color-state-warning-hover-transparent: rgb(255 250 235 / 0); --color-effects-highlight: #ffffff; - --color-effects-highlight-lightmode-off: #ffffff00; + --color-effects-highlight-lightmode-off: rgb(255 255 255 / 0); --color-effects-image-frame: #ffffff; + --color-effects-icon-border: rgb(16 24 40 / 0.08); --color-util-colors-orange-dark-orange-dark-50: #fff4ed; --color-util-colors-orange-dark-orange-dark-100: #ffe6d5; @@ -549,7 +561,7 @@ html[data-theme="light"] { --color-util-colors-orange-orange-500: #ef6820; --color-util-colors-orange-orange-600: #e04f16; --color-util-colors-orange-orange-700: #b93815; - --color-util-colors-orange-orange-100-transparent: #fdead700; + --color-util-colors-orange-orange-100-transparent: rgb(253 234 215 / 0); --color-util-colors-pink-pink-50: #fdf2fa; --color-util-colors-pink-pink-100: #fce7f6; @@ -722,8 +734,6 @@ html[data-theme="light"] { --color-util-colors-midnight-midnight-600: #5d698d; --color-util-colors-midnight-midnight-700: #3e465e; - --color-third-party-Arize: #000000; - --color-third-party-Phoenix: #000000; --color-third-party-LangChain: #1c3c3c; --color-third-party-Langfuse: #000000; --color-third-party-Github: #1b1f24; @@ -737,6 +747,9 @@ html[data-theme="light"] { --color-third-party-aws-alt: #0f1824; --color-saas-background: #fcfcfd; - --color-saas-pricing-grid-bg: #c8ceda80; + --color-saas-pricing-grid-bg: rgb(200 206 218 / 0.5); + + --color-dify-logo-dify-logo-blue: #0033ff; + --color-dify-logo-dify-logo-black: #000000; } diff --git a/web/themes/tailwind-theme-var-define.ts b/web/themes/tailwind-theme-var-define.ts index 935228199d..66a34b06ca 100644 --- a/web/themes/tailwind-theme-var-define.ts +++ b/web/themes/tailwind-theme-var-define.ts @@ -124,11 +124,15 @@ const vars = { 'components-card-bg': 'var(--color-components-card-bg)', 'components-card-border': 'var(--color-components-card-border)', 'components-card-bg-alt': 'var(--color-components-card-bg-alt)', + 'components-card-bg-transparent': 'var(--color-components-card-bg-transparent)', + 'components-card-bg-alt-transparent': 'var(--color-components-card-bg-alt-transparent)', 'components-menu-item-text': 'var(--color-components-menu-item-text)', 'components-menu-item-text-active': 'var(--color-components-menu-item-text-active)', 'components-menu-item-text-hover': 'var(--color-components-menu-item-text-hover)', 'components-menu-item-text-active-accent': 'var(--color-components-menu-item-text-active-accent)', + 'components-menu-item-bg-active': 'var(--color-components-menu-item-bg-active)', + 'components-menu-item-bg-hover': 'var(--color-components-menu-item-bg-hover)', 'components-panel-bg': 'var(--color-components-panel-bg)', 'components-panel-bg-blur': 'var(--color-components-panel-bg-blur)', @@ -386,7 +390,6 @@ const vars = { 'background-gradient-bg-fill-chat-bg-2': 'var(--color-background-gradient-bg-fill-chat-bg-2)', 'background-gradient-bg-fill-chat-bubble-bg-1': 'var(--color-background-gradient-bg-fill-chat-bubble-bg-1)', 'background-gradient-bg-fill-chat-bubble-bg-2': 'var(--color-background-gradient-bg-fill-chat-bubble-bg-2)', - 'background-gradient-bg-fill-chat-bubble-bg-3': 'var(--color-background-gradient-bg-fill-chat-bubble-bg-3)', 'background-gradient-bg-fill-debug-bg-1': 'var(--color-background-gradient-bg-fill-debug-bg-1)', 'background-gradient-bg-fill-debug-bg-2': 'var(--color-background-gradient-bg-fill-debug-bg-2)', @@ -413,6 +416,7 @@ const vars = { 'background-surface-white': 'var(--color-background-surface-white)', 'background-overlay-destructive': 'var(--color-background-overlay-destructive)', 'background-overlay-backdrop': 'var(--color-background-overlay-backdrop)', + 'background-body-transparent': 'var(--color-background-body-transparent)', 'shadow-shadow-1': 'var(--color-shadow-shadow-1)', 'shadow-shadow-3': 'var(--color-shadow-shadow-3)', @@ -430,9 +434,14 @@ const vars = { 'workflow-block-bg': 'var(--color-workflow-block-bg)', 'workflow-block-bg-transparent': 'var(--color-workflow-block-bg-transparent)', 'workflow-block-border-highlight': 'var(--color-workflow-block-border-highlight)', + 'workflow-block-wrapper-bg-1': 'var(--color-workflow-block-wrapper-bg-1)', + 'workflow-block-wrapper-bg-2': 'var(--color-workflow-block-wrapper-bg-2)', 'workflow-canvas-workflow-dot-color': 'var(--color-workflow-canvas-workflow-dot-color)', 'workflow-canvas-workflow-bg': 'var(--color-workflow-canvas-workflow-bg)', + 'workflow-canvas-workflow-top-bar-1': 'var(--color-workflow-canvas-workflow-top-bar-1)', + 'workflow-canvas-workflow-top-bar-2': 'var(--color-workflow-canvas-workflow-top-bar-2)', + 'workflow-canvas-canvas-overlay': 'var(--color-workflow-canvas-canvas-overlay)', 'workflow-link-line-active': 'var(--color-workflow-link-line-active)', 'workflow-link-line-normal': 'var(--color-workflow-link-line-normal)', @@ -517,6 +526,7 @@ const vars = { 'state-destructive-active': 'var(--color-state-destructive-active)', 'state-destructive-solid': 'var(--color-state-destructive-solid)', 'state-destructive-border': 'var(--color-state-destructive-border)', + 'state-destructive-hover-transparent': 'var(--color-state-destructive-hover-transparent)', 'state-success-hover': 'var(--color-state-success-hover)', 'state-success-hover-alt': 'var(--color-state-success-hover-alt)', @@ -527,10 +537,12 @@ const vars = { 'state-warning-hover-alt': 'var(--color-state-warning-hover-alt)', 'state-warning-active': 'var(--color-state-warning-active)', 'state-warning-solid': 'var(--color-state-warning-solid)', + 'state-warning-hover-transparent': 'var(--color-state-warning-hover-transparent)', 'effects-highlight': 'var(--color-effects-highlight)', 'effects-highlight-lightmode-off': 'var(--color-effects-highlight-lightmode-off)', 'effects-image-frame': 'var(--color-effects-image-frame)', + 'effects-icon-border': 'var(--color-effects-icon-border)', 'util-colors-orange-dark-orange-dark-50': 'var(--color-util-colors-orange-dark-orange-dark-50)', 'util-colors-orange-dark-orange-dark-100': 'var(--color-util-colors-orange-dark-orange-dark-100)', @@ -722,8 +734,6 @@ const vars = { 'util-colors-midnight-midnight-600': 'var(--color-util-colors-midnight-midnight-600)', 'util-colors-midnight-midnight-700': 'var(--color-util-colors-midnight-midnight-700)', - 'third-party-Arize': 'var(--color-third-party-Arize)', - 'third-party-Phoenix': 'var(--color-third-party-Phoenix)', 'third-party-LangChain': 'var(--color-third-party-LangChain)', 'third-party-Langfuse': 'var(--color-third-party-Langfuse)', 'third-party-Github': 'var(--color-third-party-Github)', @@ -739,5 +749,8 @@ const vars = { 'saas-background': 'var(--color-saas-background)', 'saas-pricing-grid-bg': 'var(--color-saas-pricing-grid-bg)', + 'dify-logo-dify-logo-blue': 'var(--color-dify-logo-dify-logo-blue)', + 'dify-logo-dify-logo-black': 'var(--color-dify-logo-dify-logo-black)', + } export default vars