Merge branch 'feat/plugin-auto-upgrade' into deploy/dev

pull/22338/head^2
Junyan Qin 11 months ago
commit 3798eac490
No known key found for this signature in database
GPG Key ID: 22FE3AFADC710CEB

@ -6,6 +6,7 @@ on:
- "main"
- "deploy/dev"
- "deploy/enterprise"
- "build/**"
tags:
- "*"

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

@ -98,7 +98,7 @@ const Question: FC<QuestionProps> = ({
return (
<div className='mb-2 flex justify-end last:mb-0'>
<div className={cn('group relative mr-4 flex max-w-full items-start pl-14', isEditing && 'flex-1')}>
<div className={cn('group relative mr-4 flex max-w-full items-start overflow-x-hidden pl-14', isEditing && 'flex-1')}>
<div className={cn('mr-2 gap-1', isEditing ? 'hidden' : 'flex')}>
<div
className="absolute hidden gap-0.5 rounded-[10px] border-[0.5px] border-components-actionbar-border bg-components-actionbar-bg p-0.5 shadow-md backdrop-blur-sm group-hover:flex"
@ -117,7 +117,7 @@ const Question: FC<QuestionProps> = ({
</div>
<div
ref={contentRef}
className='w-full rounded-2xl bg-background-gradient-bg-fill-chat-bubble-bg-3 px-4 py-3 text-sm text-text-primary'
className='bg-background-gradient-bg-fill-chat-bubble-bg-3 w-full rounded-2xl px-4 py-3 text-sm text-text-primary'
style={theme?.chatBubbleColorStyle ? CssTransform(theme.chatBubbleColorStyle) : {}}
>
{

File diff suppressed because one or more lines are too long

@ -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 = (
},
) => <IconBase {...props} ref={ref} data={data as IconData} />
Icon.displayName = 'OpenaiTeal'
Icon.displayName = 'OpenaiTale'
export default Icon

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

@ -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 && (
<Tooltip
popupContent={t('plugin.privilege.title')}
>

@ -113,7 +113,7 @@ const ToolPicker: FC<Props> = ({
<PortalToFollowElem
placement='top'
offset={0}
open={isShow}
open={true}
onOpenChange={onShowChange}
>
<PortalToFollowElemTrigger

@ -11,6 +11,8 @@ import { uniqueId } from 'lodash-es'
const i18nPrefix = 'workflow.nodes.questionClassifiers'
type Props = {
className?: string
headerClassName?: string
nodeId: string
payload: Topic
onChange: (payload: Topic) => void
@ -21,6 +23,8 @@ type Props = {
}
const ClassItem: FC<Props> = ({
className,
headerClassName,
nodeId,
payload,
onChange,
@ -49,6 +53,8 @@ const ClassItem: FC<Props> = ({
return (
<Editor
className={className}
headerClassName={headerClassName}
title={`${t(`${i18nPrefix}.class`)} ${index}`}
placeholder={t(`${i18nPrefix}.topicPlaceholder`)!}
value={payload.name}

@ -8,6 +8,9 @@ import AddButton from '../../_base/components/add-button'
import Item from './class-item'
import type { Topic } from '@/app/components/workflow/nodes/question-classifier/types'
import type { ValueSelector, Var } from '@/app/components/workflow/types'
import { ReactSortable } from 'react-sortablejs'
import { noop } from 'lodash-es'
import cn from '@/utils/classnames'
const i18nPrefix = 'workflow.nodes.questionClassifiers'
@ -17,6 +20,7 @@ type Props = {
onChange: (list: Topic[]) => void
readonly?: boolean
filterVar: (payload: Var, valueSelector: ValueSelector) => boolean
handleSortTopic?: (newTopics: (Topic & { id: string })[]) => void
}
const ClassList: FC<Props> = ({
@ -25,6 +29,7 @@ const ClassList: FC<Props> = ({
onChange,
readonly,
filterVar,
handleSortTopic = noop,
}) => {
const { t } = useTranslation()
const { handleEdgeDeleteByDeleteBranch } = useEdgesInteractions()
@ -55,22 +60,48 @@ const ClassList: FC<Props> = ({
}
}, [list, onChange, handleEdgeDeleteByDeleteBranch, nodeId])
const topicCount = list.length
const handleSideWidth = 3
// Todo Remove; edit topic name
return (
<div className='space-y-2'>
<ReactSortable
list={list.map(item => ({ ...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 (
<Item
nodeId={nodeId}
key={list[index].id}
payload={item}
onChange={handleClassChange(index)}
onRemove={handleRemoveClass(index)}
index={index + 1}
readonly={readonly}
filterVar={filterVar}
/>
<div key={item.id}
className={cn(
'group relative rounded-[10px] bg-components-panel-bg',
`-ml-${handleSideWidth} min-h-[40px] px-0 py-0`,
)}>
<div >
<Item
className={cn(canDrag && 'handle')}
headerClassName={cn(canDrag && 'cursor-grab')}
nodeId={nodeId}
key={list[index].id}
payload={item}
onChange={handleClassChange(index)}
onRemove={handleRemoveClass(index)}
index={index + 1}
readonly={readonly}
filterVar={filterVar}
/>
</div>
</div>
)
})
}
@ -81,7 +112,7 @@ const ClassList: FC<Props> = ({
/>
)}
</div>
</ReactSortable>
)
}
export default React.memo(ClassList)

@ -40,6 +40,7 @@ const Panel: FC<NodePanelProps<QuestionClassifierNodeType>> = ({
handleVisionResolutionChange,
handleVisionResolutionEnabledChange,
filterVar,
handleSortTopic,
} = useConfig(id, data)
const model = inputs.model
@ -99,6 +100,7 @@ const Panel: FC<NodePanelProps<QuestionClassifierNodeType>> = ({
onChange={handleTopicsChange}
readonly={readOnly}
filterVar={filterVar}
handleSortTopic={handleSortTopic}
/>
</Field>
<Split />

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

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

@ -364,6 +364,7 @@ const translation = {
ms: 'Frau',
retries: '{{num}} Wiederholungen',
},
typeSwitch: {},
},
start: {
required: 'erforderlich',

@ -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 🤖',

@ -364,6 +364,7 @@ const translation = {
retries: '{{num}} Reintentos',
retry: 'Reintentar',
},
typeSwitch: {},
},
start: {
required: 'requerido',

@ -176,6 +176,7 @@ const translation = {
title: 'بافندگی',
description: 'ویو یک پلتفرم متن باز برای ارزیابی، آزمایش و نظارت بر برنامه‌های LLM است.',
},
aliyun: {},
},
answerIcon: {
descriptionInExplore: 'آیا از نماد web app برای جایگزینی 🤖 در Explore استفاده کنیم یا خیر',

@ -364,6 +364,7 @@ const translation = {
retrySuccessful: 'امتحان مجدد با موفقیت انجام دهید',
retryFailedTimes: '{{بار}} تلاش های مجدد ناموفق بود',
},
typeSwitch: {},
},
start: {
required: 'الزامی',

@ -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: 'Sil faut utiliser licône web app pour remplacer 🤖 dans lapplication partagée',

@ -364,6 +364,7 @@ const translation = {
ms: 'ms',
retries: '{{num}} Tentatives',
},
typeSwitch: {},
},
start: {
required: 'requis',

@ -172,6 +172,7 @@ const translation = {
title: 'बुनना',
description: 'वीव एक ओपन-सोर्स प्लेटफ़ॉर्म है जो LLM अनुप्रयोगों का मूल्यांकन, परीक्षण और निगरानी करने के लिए है।',
},
aliyun: {},
},
answerIcon: {
title: 'बदलने 🤖 के लिए web app चिह्न का उपयोग करें',

@ -376,6 +376,7 @@ const translation = {
retry: 'पुनर्प्रयास',
retryOnFailure: 'विफलता पर पुनः प्रयास करें',
},
typeSwitch: {},
},
start: {
required: 'आवश्यक',

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

@ -379,6 +379,7 @@ const translation = {
retryFailed: 'Nuovo tentativo non riuscito',
ms: 'ms',
},
typeSwitch: {},
},
start: {
required: 'richiesto',

@ -180,6 +180,7 @@ const translation = {
title: '織る',
description: 'Weave は、LLM アプリケーションを評価、テスト、および監視するためのオープンソースプラットフォームです。',
},
aliyun: {},
},
answerIcon: {
title: 'Web アプリアイコンを使用して🤖を置き換える',

@ -228,7 +228,6 @@ const translation = {
publishTip: 'アプリが公開されていません。まずアプリを公開してください。',
},
},
}
export default translation

@ -369,6 +369,7 @@ const translation = {
ms: 'ミリ秒',
retries: '再試行回数:{{num}}',
},
typeSwitch: {},
},
start: {
required: '必須',

@ -192,6 +192,7 @@ const translation = {
description:
'Weave 는 LLM 애플리케이션을 평가하고 테스트하며 모니터링하기 위한 오픈 소스 플랫폼입니다.',
},
aliyun: {},
},
answerIcon: {
description:

@ -388,6 +388,7 @@ const translation = {
ms: '미에스',
retries: '{{숫자}} 재시도',
},
typeSwitch: {},
},
start: {
required: '필수',

@ -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 🤖.',

@ -364,6 +364,7 @@ const translation = {
retryFailedTimes: '{{times}} ponawianie prób nie powiodło się',
ms: 'Ms',
},
typeSwitch: {},
},
start: {
required: 'wymagane',

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

@ -364,6 +364,7 @@ const translation = {
ms: 'ms',
retries: '{{num}} Tentativas',
},
typeSwitch: {},
},
start: {
required: 'requerido',

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

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

@ -176,6 +176,7 @@ const translation = {
description: 'Weave — это открытая платформа для оценки, тестирования и мониторинга приложений LLM.',
title: 'Ткать',
},
aliyun: {},
},
answerIcon: {
title: 'Использование значка web app для замены 🤖',

@ -364,6 +364,7 @@ const translation = {
retryFailedTimes: 'Повторные попытки {{times}} не увенчались успехом',
retries: '{{число}} Повторных попыток',
},
typeSwitch: {},
},
start: {
required: 'обязательно',

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

@ -366,6 +366,7 @@ const translation = {
},
insertVarTip: 'Vstavite spremenljivko',
outputVars: 'Izhodne spremenljivke',
typeSwitch: {},
},
start: {
outputVars: {

@ -177,6 +177,7 @@ const translation = {
title: 'ทอ',
description: 'Weave เป็นแพลตฟอร์มโอเพนซอร์สสำหรับการประเมินผล ทดสอบ และตรวจสอบแอปพลิเคชัน LLM',
},
aliyun: {},
},
mermaid: {
handDrawn: 'วาดด้วยมือ',

@ -364,6 +364,7 @@ const translation = {
retries: '{{num}} ลอง',
ms: 'นางสาว',
},
typeSwitch: {},
},
start: {
required: 'ต้องระบุ',

@ -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ğı',

@ -364,6 +364,7 @@ const translation = {
retrying: 'Yeniden deneniyor...',
ms: 'Ms',
},
typeSwitch: {},
},
start: {
required: 'gerekli',

@ -172,6 +172,7 @@ const translation = {
title: 'Ткати',
description: 'Weave є платформою з відкритим кодом для оцінки, тестування та моніторингу LLM додатків.',
},
aliyun: {},
},
answerIcon: {
title: 'Використовуйте піктограму web app для заміни 🤖',

@ -364,6 +364,7 @@ const translation = {
retryFailedTimes: '{{times}} повторні спроби не вдалися',
retryTimes: 'Повторіть спробу {{times}} у разі невдачі',
},
typeSwitch: {},
},
start: {
required: 'обов\'язковий',

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

@ -364,6 +364,7 @@ const translation = {
times: 'lần',
ms: 'Ms',
},
typeSwitch: {},
},
start: {
required: 'bắt buộc',

@ -171,6 +171,7 @@ const translation = {
title: '編織',
description: 'Weave 是一個開源平台,用於評估、測試和監控大型語言模型應用程序。',
},
aliyun: {},
},
answerIcon: {
descriptionInExplore: '是否使用 web app 圖示在 Explore 中取代 🤖',

@ -364,6 +364,7 @@ const translation = {
ms: '毫秒',
retries: '{{num}}重試',
},
typeSwitch: {},
},
start: {
required: '必填',

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

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

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

Loading…
Cancel
Save