From 3d57a9ccdc4bc42e025e3515ebc35380c25ef5ed Mon Sep 17 00:00:00 2001 From: Yongtao Huang Date: Mon, 1 Sep 2025 09:45:07 +0800 Subject: [PATCH 01/30] Fix never hit `(!code || code.length === 0)` (#24860) --- web/service/use-share.ts | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/web/service/use-share.ts b/web/service/use-share.ts index 6845a2f3c7..267975fd38 100644 --- a/web/service/use-share.ts +++ b/web/service/use-share.ts @@ -6,12 +6,7 @@ const NAME_SPACE = 'webapp' export const useGetWebAppAccessModeByCode = (code: string | null) => { return useQuery({ queryKey: [NAME_SPACE, 'appAccessMode', code], - queryFn: () => { - if (!code || code.length === 0) - return Promise.reject(new Error('App code is required to get access mode')) - - return getAppAccessModeByAppCode(code) - }, + queryFn: () => getAppAccessModeByAppCode(code!), enabled: !!code, }) } From c45c22b1b2ca3eeca1ec70e39201ba3db5156a72 Mon Sep 17 00:00:00 2001 From: NeatGuyCoding <15627489+NeatGuyCoding@users.noreply.github.com> Date: Mon, 1 Sep 2025 10:04:05 +0800 Subject: [PATCH 02/30] fix translation of all oauth.ts (#24855) --- web/i18n/de-DE/oauth.ts | 6 +++--- web/i18n/en-US/oauth.ts | 6 +++--- web/i18n/es-ES/oauth.ts | 4 ++-- web/i18n/fa-IR/oauth.ts | 4 ++-- web/i18n/fr-FR/oauth.ts | 4 ++-- web/i18n/hi-IN/oauth.ts | 6 +++--- web/i18n/it-IT/oauth.ts | 4 ++-- web/i18n/ja-JP/oauth.ts | 8 ++++---- web/i18n/ko-KR/oauth.ts | 8 ++++---- web/i18n/pl-PL/oauth.ts | 4 ++-- web/i18n/pt-BR/oauth.ts | 4 ++-- web/i18n/ro-RO/oauth.ts | 4 ++-- web/i18n/ru-RU/oauth.ts | 6 +++--- web/i18n/sl-SI/oauth.ts | 4 ++-- web/i18n/th-TH/oauth.ts | 4 ++-- web/i18n/tr-TR/oauth.ts | 4 ++-- web/i18n/uk-UA/oauth.ts | 4 ++-- web/i18n/vi-VN/oauth.ts | 4 ++-- 18 files changed, 44 insertions(+), 44 deletions(-) diff --git a/web/i18n/de-DE/oauth.ts b/web/i18n/de-DE/oauth.ts index 6eb684fa3c..7478a4afd5 100644 --- a/web/i18n/de-DE/oauth.ts +++ b/web/i18n/de-DE/oauth.ts @@ -1,8 +1,8 @@ const translation = { tips: { common: 'Wir respektieren Ihre Privatsphäre und werden diese Informationen nur verwenden, um Ihre Erfahrung mit unseren Entwickler-Tools zu verbessern.', - notLoggedIn: 'möchte auf Ihr Dify Cloud-Konto zugreifen', - loggedIn: 'möchte auf die folgenden Informationen aus Ihrem Dify Cloud-Konto zugreifen.', + notLoggedIn: 'Diese App möchte auf Ihr Dify Cloud-Konto zugreifen', + loggedIn: 'Diese App möchte auf die folgenden Informationen aus Ihrem Dify Cloud-Konto zugreifen.', needLogin: 'Bitte melden Sie sich an, um zu autorisieren.', }, scopes: { @@ -21,7 +21,7 @@ const translation = { login: 'Anmelden', unknownApp: 'Unbekannte App', continue: 'Fortsetzen', - connect: 'Verbinde zu', + connect: 'Verbinden mit', } export default translation diff --git a/web/i18n/en-US/oauth.ts b/web/i18n/en-US/oauth.ts index ff71487fcd..5215330587 100644 --- a/web/i18n/en-US/oauth.ts +++ b/web/i18n/en-US/oauth.ts @@ -1,7 +1,7 @@ const translation = { tips: { - loggedIn: 'wants to access the following information from your Dify Cloud account.', - notLoggedIn: 'wants to access your Dify Cloud account', + loggedIn: 'This app wants to access the following information from your Dify Cloud account.', + notLoggedIn: 'This app wants to access your Dify Cloud account', needLogin: 'Please log in to authorize', common: 'We respect your privacy and will only use this information to enhance your experience with our developer tools.', }, @@ -18,7 +18,7 @@ const translation = { }, error: { invalidParams: 'Invalid parameters', - authorizeFailed: 'Authorize failed', + authorizeFailed: 'Authorization failed', authAppInfoFetchFailed: 'Failed to fetch app info for authorization', }, unknownApp: 'Unknown App', diff --git a/web/i18n/es-ES/oauth.ts b/web/i18n/es-ES/oauth.ts index fe6093ebf7..23d7eaa895 100644 --- a/web/i18n/es-ES/oauth.ts +++ b/web/i18n/es-ES/oauth.ts @@ -1,8 +1,8 @@ const translation = { tips: { needLogin: 'Por favor inicie sesión para autorizar', - notLoggedIn: 'quiere acceder a su cuenta de Dify Cloud', - loggedIn: 'quiere acceder a la siguiente información de su cuenta de Dify Cloud.', + notLoggedIn: 'Esta aplicación quiere acceder a su cuenta de Dify Cloud', + loggedIn: 'Esta aplicación quiere acceder a la siguiente información de su cuenta de Dify Cloud.', common: 'Respetamos su privacidad y solo utilizaremos esta información para mejorar su experiencia con nuestras herramientas para desarrolladores.', }, scopes: { diff --git a/web/i18n/fa-IR/oauth.ts b/web/i18n/fa-IR/oauth.ts index cb8ea498fa..380b4f78b5 100644 --- a/web/i18n/fa-IR/oauth.ts +++ b/web/i18n/fa-IR/oauth.ts @@ -1,8 +1,8 @@ const translation = { tips: { needLogin: 'لطفاً برای تأیید وارد شوید', - notLoggedIn: 'می‌خواهد به حساب Dify Cloud شما دسترسی پیدا کند', - loggedIn: 'می‌خواهد به اطلاعات زیر از حساب ابر دیفی شما دسترسی پیدا کند.', + notLoggedIn: 'این برنامه می‌خواهد به حساب Dify Cloud شما دسترسی پیدا کند', + loggedIn: 'این برنامه می‌خواهد به اطلاعات زیر از حساب ابر دیفی شما دسترسی پیدا کند.', common: 'ما به حریم خصوصی شما احترام می‌گذاریم و تنها از این اطلاعات برای بهبود تجربه شما با ابزارهای توسعه‌دهنده‌مان استفاده خواهیم کرد.', }, scopes: { diff --git a/web/i18n/fr-FR/oauth.ts b/web/i18n/fr-FR/oauth.ts index b2fa71e143..7ce46b9d5e 100644 --- a/web/i18n/fr-FR/oauth.ts +++ b/web/i18n/fr-FR/oauth.ts @@ -1,9 +1,9 @@ const translation = { tips: { needLogin: 'Veuillez vous connecter pour autoriser', - notLoggedIn: 'veut accéder à votre compte Dify Cloud', + notLoggedIn: 'Cette application veut accéder à votre compte Dify Cloud', common: 'Nous respectons votre vie privée et n\'utiliserons ces informations que pour améliorer votre expérience avec nos outils de développement.', - loggedIn: 'veut accéder aux informations suivantes de votre compte Dify Cloud.', + loggedIn: 'Cette application veut accéder aux informations suivantes de votre compte Dify Cloud.', }, scopes: { email: 'E-mail', diff --git a/web/i18n/hi-IN/oauth.ts b/web/i18n/hi-IN/oauth.ts index 7cdba1fe5b..a2e7bb9e36 100644 --- a/web/i18n/hi-IN/oauth.ts +++ b/web/i18n/hi-IN/oauth.ts @@ -1,9 +1,9 @@ const translation = { tips: { needLogin: 'कृपया प्राधिकरण के लिए लॉग इन करें', - notLoggedIn: 'आप आपके Dify Cloud खाते तक पहुंचना चाहते हैं', + notLoggedIn: 'यह ऐप आपके Dify Cloud खाते तक पहुंचना चाहता है', common: 'हम आपकी गोपनीयता का सम्मान करते हैं और इस जानकारी का उपयोग केवल आपके हमारे विकास उपकरणों के साथ अनुभव को बेहतर बनाने के लिए करेंगे।', - loggedIn: 'आप आपके Dify Cloud खाते से निम्नलिखित जानकारी तक पहुंचना चाहते हैं।', + loggedIn: 'यह ऐप आपके Dify Cloud खाते से निम्नलिखित जानकारी तक पहुंचना चाहता है।', }, scopes: { name: 'नाम', @@ -13,7 +13,7 @@ const translation = { timezone: 'समय क्षेत्र', }, error: { - authorizeFailed: 'अनु autorización विफल', + authorizeFailed: 'प्राधिकरण विफल', invalidParams: 'अमान्य पैरामीटर', authAppInfoFetchFailed: 'प्राधिकरण के लिए ऐप जानकारी प्राप्त करने में असफल हुआ', }, diff --git a/web/i18n/it-IT/oauth.ts b/web/i18n/it-IT/oauth.ts index 3955a3997e..4220666a9a 100644 --- a/web/i18n/it-IT/oauth.ts +++ b/web/i18n/it-IT/oauth.ts @@ -1,7 +1,7 @@ const translation = { tips: { - notLoggedIn: 'vuole accedere al tuo account Dify Cloud', - loggedIn: 'vuole accedere alle seguenti informazioni dal tuo account Dify Cloud.', + notLoggedIn: 'Questa app vuole accedere al tuo account Dify Cloud', + loggedIn: 'Questa app vuole accedere alle seguenti informazioni dal tuo account Dify Cloud.', common: 'Rispettiamo la tua privacy e utilizzeremo queste informazioni solo per migliorare la tua esperienza con i nostri strumenti per sviluppatori.', needLogin: 'Per favore, accedi per autorizzare', }, diff --git a/web/i18n/ja-JP/oauth.ts b/web/i18n/ja-JP/oauth.ts index 239892c03e..54322e1a48 100644 --- a/web/i18n/ja-JP/oauth.ts +++ b/web/i18n/ja-JP/oauth.ts @@ -1,8 +1,8 @@ const translation = { tips: { - notLoggedIn: 'あなたのDify Cloudアカウントにアクセスしたいです', + notLoggedIn: 'このアプリはあなたのDify Cloudアカウントにアクセスしたいです', needLogin: 'ログインして認証してください', - loggedIn: 'あなたのDify Cloudアカウントから以下の情報にアクセスしたいと思っています。', + loggedIn: 'このアプリはあなたのDify Cloudアカウントから以下の情報にアクセスしたいと思っています。', common: '私たちはあなたのプライバシーを尊重し、この情報を私たちの開発者ツールによる体験を向上させるためにのみ使用します。', }, scopes: { @@ -17,10 +17,10 @@ const translation = { invalidParams: '無効なパラメータ', authAppInfoFetchFailed: '認証のためのアプリ情報の取得に失敗しました', }, - unknownApp: '未知のアプリ', + unknownApp: '不明なアプリ', login: 'ログイン', switchAccount: 'アカウントを切り替える', - continue: '続けてください', + continue: '続行', connect: '接続する', } diff --git a/web/i18n/ko-KR/oauth.ts b/web/i18n/ko-KR/oauth.ts index 7f86a20ce0..5c13240823 100644 --- a/web/i18n/ko-KR/oauth.ts +++ b/web/i18n/ko-KR/oauth.ts @@ -1,8 +1,8 @@ const translation = { tips: { needLogin: '로그인하여 인증해 주세요.', - notLoggedIn: 'Dify Cloud 계정에 접근하고 싶어합니다.', - loggedIn: '다음 정보를 귀하의 Dify Cloud 계정에서 액세스하려고 합니다.', + notLoggedIn: '이 앱은 Dify Cloud 계정에 접근하고 싶어합니다.', + loggedIn: '이 앱은 다음 정보를 귀하의 Dify Cloud 계정에서 액세스하려고 합니다.', common: '우리는 귀하의 개인 정보를 존중하며, 이 정보를 개발자 도구를 통한 귀하의 경험 향상에만 사용할 것입니다.', }, scopes: { @@ -17,11 +17,11 @@ const translation = { authorizeFailed: '권한 부여 실패', authAppInfoFetchFailed: '인증을 위한 앱 정보를 가져오지 못했습니다.', }, - continue: '계속하다', + continue: '계속', unknownApp: '알 수 없는 앱', switchAccount: '계정 전환', login: '로그인', - connect: '연결하다', + connect: '연결', } export default translation diff --git a/web/i18n/pl-PL/oauth.ts b/web/i18n/pl-PL/oauth.ts index e8cf0a5f62..2136b29c90 100644 --- a/web/i18n/pl-PL/oauth.ts +++ b/web/i18n/pl-PL/oauth.ts @@ -1,9 +1,9 @@ const translation = { tips: { needLogin: 'Proszę się zalogować, aby autoryzować', - notLoggedIn: 'chce uzyskać dostęp do twojego konta Dify Cloud', + notLoggedIn: 'Ta aplikacja chce uzyskać dostęp do twojego konta Dify Cloud', common: 'Szanujemy Twoją prywatność i będziemy wykorzystywać te informacje tylko w celu ulepszenia Twojego doświadczenia z naszymi narzędziami deweloperskimi.', - loggedIn: 'chce uzyskać dostęp do następujących informacji z twojego konta Dify Cloud.', + loggedIn: 'Ta aplikacja chce uzyskać dostęp do następujących informacji z twojego konta Dify Cloud.', }, scopes: { timezone: 'Strefa czasowa', diff --git a/web/i18n/pt-BR/oauth.ts b/web/i18n/pt-BR/oauth.ts index 2e45480f29..eba5d4e738 100644 --- a/web/i18n/pt-BR/oauth.ts +++ b/web/i18n/pt-BR/oauth.ts @@ -1,7 +1,7 @@ const translation = { tips: { - notLoggedIn: 'quer acessar sua conta do Dify Cloud', - loggedIn: 'quer acessar as seguintes informações da sua conta Dify Cloud.', + notLoggedIn: 'Este aplicativo quer acessar sua conta do Dify Cloud', + loggedIn: 'Este aplicativo quer acessar as seguintes informações da sua conta Dify Cloud.', common: 'Respeitamos sua privacidade e usaremos essas informações apenas para melhorar sua experiência com nossas ferramentas de desenvolvedor.', needLogin: 'Por favor, faça login para autorizar', }, diff --git a/web/i18n/ro-RO/oauth.ts b/web/i18n/ro-RO/oauth.ts index 0eb9222093..c21322d2f2 100644 --- a/web/i18n/ro-RO/oauth.ts +++ b/web/i18n/ro-RO/oauth.ts @@ -1,8 +1,8 @@ const translation = { tips: { needLogin: 'Vă rugăm să vă conectați pentru a autoriza', - loggedIn: 'vrea să acceseze următoarele informații din contul tău Dify Cloud.', - notLoggedIn: 'vrea să acceseze contul tău Dify Cloud', + loggedIn: 'Această aplicație vrea să acceseze următoarele informații din contul tău Dify Cloud.', + notLoggedIn: 'Această aplicație vrea să acceseze contul tău Dify Cloud', common: 'Respectăm confidențialitatea dvs. și vom folosi aceste informații doar pentru a îmbunătăți experiența dvs. cu instrumentele noastre pentru dezvoltatori.', }, scopes: { diff --git a/web/i18n/ru-RU/oauth.ts b/web/i18n/ru-RU/oauth.ts index 26a84100d5..d530b8c780 100644 --- a/web/i18n/ru-RU/oauth.ts +++ b/web/i18n/ru-RU/oauth.ts @@ -1,8 +1,8 @@ const translation = { tips: { needLogin: 'Пожалуйста, войдите, чтобы авторизоваться', - notLoggedIn: 'хочет получить доступ к вашей учетной записи Dify Cloud', - loggedIn: 'хочет получить следующую информацию из вашего аккаунта Dify Cloud.', + notLoggedIn: 'Это приложение хочет получить доступ к вашей учетной записи Dify Cloud', + loggedIn: 'Это приложение хочет получить следующую информацию из вашего аккаунта Dify Cloud.', common: 'Мы уважаем вашу конфиденциальность и будем использовать эту информацию только для улучшения вашего опыта с нашими инструментами разработчика.', }, scopes: { @@ -17,7 +17,7 @@ const translation = { authorizeFailed: 'Авторизация не удалась', authAppInfoFetchFailed: 'Не удалось получить информацию об приложении для авторизации', }, - continue: 'Продолжайте', + continue: 'Продолжить', connect: 'Подключиться к', switchAccount: 'Сменить аккаунт', unknownApp: 'Неизвестное приложение', diff --git a/web/i18n/sl-SI/oauth.ts b/web/i18n/sl-SI/oauth.ts index 2a99e1a6e3..f03bfadd50 100644 --- a/web/i18n/sl-SI/oauth.ts +++ b/web/i18n/sl-SI/oauth.ts @@ -1,7 +1,7 @@ const translation = { tips: { - notLoggedIn: 'želi dostopati do vašega Dify Cloud računa', - loggedIn: 'želi dostopati do naslednjih informacij iz vašega računa Dify Cloud.', + notLoggedIn: 'Ta aplikacija želi dostopati do vašega Dify Cloud računa', + loggedIn: 'Ta aplikacija želi dostopati do naslednjih informacij iz vašega računa Dify Cloud.', common: 'Soočamo se z vašo zasebnostjo in te informacije bomo uporabili le za izboljšanje vaših izkušenj z našimi orodji za razvijalce.', needLogin: 'Prosimo, prijavite se za avtorizacijo', }, diff --git a/web/i18n/th-TH/oauth.ts b/web/i18n/th-TH/oauth.ts index 74b5d123f1..626510b684 100644 --- a/web/i18n/th-TH/oauth.ts +++ b/web/i18n/th-TH/oauth.ts @@ -1,8 +1,8 @@ const translation = { tips: { needLogin: 'โปรดเข้าสู่ระบบเพื่ออนุญาต', - notLoggedIn: 'ต้องการเข้าถึงบัญชี Dify Cloud ของคุณ', - loggedIn: 'ต้องการเข้าถึงข้อมูลต่อไปนี้จากบัญชี Dify Cloud ของคุณ.', + notLoggedIn: 'แอปพลิเคชันนี้ต้องการเข้าถึงบัญชี Dify Cloud ของคุณ', + loggedIn: 'แอปพลิเคชันนี้ต้องการเข้าถึงข้อมูลต่อไปนี้จากบัญชี Dify Cloud ของคุณ.', common: 'เรามีความเคารพต่อความเป็นส่วนตัวของคุณและจะใช้ข้อมูลนี้เพื่อปรับปรุงประสบการณ์ของคุณกับเครื่องมือนักพัฒนาของเราเท่านั้น.', }, scopes: { diff --git a/web/i18n/tr-TR/oauth.ts b/web/i18n/tr-TR/oauth.ts index 65196bcfe3..3f71cdf483 100644 --- a/web/i18n/tr-TR/oauth.ts +++ b/web/i18n/tr-TR/oauth.ts @@ -1,8 +1,8 @@ const translation = { tips: { - notLoggedIn: 'Dify Cloud hesabınıza erişmek istiyor', + notLoggedIn: 'Bu uygulama Dify Cloud hesabınıza erişmek istiyor', common: 'Gizliliğinize saygı gösteriyoruz ve bu bilgiyi yalnızca geliştirici araçlarımızla deneyiminizi geliştirmek için kullanacağız.', - loggedIn: 'Dify Cloud hesabınızdaki aşağıdaki bilgilere erişmek istiyor.', + loggedIn: 'Bu uygulama Dify Cloud hesabınızdaki aşağıdaki bilgilere erişmek istiyor.', needLogin: 'Lütfen yetkilendirmek için giriş yapın', }, scopes: { diff --git a/web/i18n/uk-UA/oauth.ts b/web/i18n/uk-UA/oauth.ts index 0fc6018059..a2510c6efe 100644 --- a/web/i18n/uk-UA/oauth.ts +++ b/web/i18n/uk-UA/oauth.ts @@ -1,8 +1,8 @@ const translation = { tips: { - notLoggedIn: 'хоче отримати доступ до вашого облікового запису Dify Cloud', + notLoggedIn: 'Цей додаток хоче отримати доступ до вашого облікового запису Dify Cloud', needLogin: 'Будь ласка, увійдіть, щоб авторизуватися.', - loggedIn: 'хоче отримати доступ до наступної інформації з вашого облікового запису Dify Cloud.', + loggedIn: 'Цей додаток хоче отримати доступ до наступної інформації з вашого облікового запису Dify Cloud.', common: 'Ми поважаємо вашу конфіденційність і використовуватимемо цю інформацію лише для покращення вашого досвіду з нашими інструментами для розробників.', }, scopes: { diff --git a/web/i18n/vi-VN/oauth.ts b/web/i18n/vi-VN/oauth.ts index 2c1c9ba37d..dc4c1b39bc 100644 --- a/web/i18n/vi-VN/oauth.ts +++ b/web/i18n/vi-VN/oauth.ts @@ -1,8 +1,8 @@ const translation = { tips: { needLogin: 'Vui lòng đăng nhập để xác thực', - notLoggedIn: 'muốn truy cập vào tài khoản Dify Cloud của bạn', - loggedIn: 'muốn truy cập thông tin sau từ tài khoản Dify Cloud của bạn.', + notLoggedIn: 'Ứng dụng này muốn truy cập vào tài khoản Dify Cloud của bạn', + loggedIn: 'Ứng dụng này muốn truy cập thông tin sau từ tài khoản Dify Cloud của bạn.', common: 'Chúng tôi tôn trọng quyền riêng tư của bạn và sẽ chỉ sử dụng thông tin này để cải thiện trải nghiệm của bạn với các công cụ phát triển của chúng tôi.', }, scopes: { From b8d8dddd5a06efd1816cd496d4d92b1476aafd00 Mon Sep 17 00:00:00 2001 From: Asuka Minato Date: Mon, 1 Sep 2025 11:04:24 +0900 Subject: [PATCH 03/30] example of decorator typing (#24857) Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> --- api/controllers/inner_api/wraps.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/api/controllers/inner_api/wraps.py b/api/controllers/inner_api/wraps.py index c5aa318f58..de4f1da801 100644 --- a/api/controllers/inner_api/wraps.py +++ b/api/controllers/inner_api/wraps.py @@ -1,8 +1,12 @@ from base64 import b64encode +from collections.abc import Callable from functools import wraps from hashlib import sha1 from hmac import new as hmac_new +from typing import ParamSpec, TypeVar +P = ParamSpec("P") +R = TypeVar("R") from flask import abort, request from configs import dify_config @@ -10,9 +14,9 @@ from extensions.ext_database import db from models.model import EndUser -def billing_inner_api_only(view): +def billing_inner_api_only(view: Callable[P, R]): @wraps(view) - def decorated(*args, **kwargs): + def decorated(*args: P.args, **kwargs: P.kwargs): if not dify_config.INNER_API: abort(404) @@ -26,9 +30,9 @@ def billing_inner_api_only(view): return decorated -def enterprise_inner_api_only(view): +def enterprise_inner_api_only(view: Callable[P, R]): @wraps(view) - def decorated(*args, **kwargs): + def decorated(*args: P.args, **kwargs: P.kwargs): if not dify_config.INNER_API: abort(404) @@ -78,9 +82,9 @@ def enterprise_inner_api_user_auth(view): return decorated -def plugin_inner_api_only(view): +def plugin_inner_api_only(view: Callable[P, R]): @wraps(view) - def decorated(*args, **kwargs): + def decorated(*args: P.args, **kwargs: P.kwargs): if not dify_config.PLUGIN_DAEMON_KEY: abort(404) From c45d676477c16807f2a71df94b7646fdc38f378e Mon Sep 17 00:00:00 2001 From: NeatGuyCoding <15627489+NeatGuyCoding@users.noreply.github.com> Date: Mon, 1 Sep 2025 10:05:19 +0800 Subject: [PATCH 04/30] remove duplicated authorization header handling and bearer should be case-insensitive (#24852) --- api/controllers/console/auth/oauth_server.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/api/controllers/console/auth/oauth_server.py b/api/controllers/console/auth/oauth_server.py index 19ca464a79..0e6e746a8b 100644 --- a/api/controllers/console/auth/oauth_server.py +++ b/api/controllers/console/auth/oauth_server.py @@ -44,22 +44,19 @@ def oauth_server_access_token_required(view): if not oauth_provider_app or not isinstance(oauth_provider_app, OAuthProviderApp): raise BadRequest("Invalid oauth_provider_app") - if not request.headers.get("Authorization"): - raise BadRequest("Authorization is required") - authorization_header = request.headers.get("Authorization") if not authorization_header: raise BadRequest("Authorization header is required") - parts = authorization_header.split(" ") + parts = authorization_header.strip().split(" ") if len(parts) != 2: raise BadRequest("Invalid Authorization header format") - token_type = parts[0] - if token_type != "Bearer": + token_type = parts[0].strip() + if token_type.lower() != "bearer": raise BadRequest("token_type is invalid") - access_token = parts[1] + access_token = parts[1].strip() if not access_token: raise BadRequest("access_token is required") From 2e6e414a9ed36c5b23af26755780fd59234fbc5d Mon Sep 17 00:00:00 2001 From: NeatGuyCoding <15627489+NeatGuyCoding@users.noreply.github.com> Date: Mon, 1 Sep 2025 10:05:54 +0800 Subject: [PATCH 05/30] the conversion OAuthGrantType(parsed_args["grant_type"]) can raise ValueError for invalid values which is not caught and will produce a 500 (#24854) --- api/controllers/console/auth/oauth_server.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/api/controllers/console/auth/oauth_server.py b/api/controllers/console/auth/oauth_server.py index 0e6e746a8b..f730cfa3fe 100644 --- a/api/controllers/console/auth/oauth_server.py +++ b/api/controllers/console/auth/oauth_server.py @@ -122,7 +122,10 @@ class OAuthServerUserTokenApi(Resource): parser.add_argument("refresh_token", type=str, required=False, location="json") parsed_args = parser.parse_args() - grant_type = OAuthGrantType(parsed_args["grant_type"]) + try: + grant_type = OAuthGrantType(parsed_args["grant_type"]) + except ValueError: + raise BadRequest("invalid grant_type") if grant_type == OAuthGrantType.AUTHORIZATION_CODE: if not parsed_args["code"]: @@ -160,8 +163,6 @@ class OAuthServerUserTokenApi(Resource): "refresh_token": refresh_token, } ) - else: - raise BadRequest("invalid grant_type") class OAuthServerUserAccountApi(Resource): From f11131f8b502b635c0ad59d95ec3c0d12149957f Mon Sep 17 00:00:00 2001 From: 17hz <0x149527@gmail.com> Date: Mon, 1 Sep 2025 13:50:33 +0800 Subject: [PATCH 06/30] fix: basepath did not read from the environment variable (#24870) --- web/next.config.js | 4 +--- web/utils/var-basePath.js | 6 ------ web/utils/var.ts | 2 +- 3 files changed, 2 insertions(+), 10 deletions(-) delete mode 100644 web/utils/var-basePath.js diff --git a/web/next.config.js b/web/next.config.js index 6920a47fbf..e039ba9284 100644 --- a/web/next.config.js +++ b/web/next.config.js @@ -1,4 +1,3 @@ -const { basePath, assetPrefix } = require('./utils/var-basePath') const { codeInspectorPlugin } = require('code-inspector-plugin') const withMDX = require('@next/mdx')({ extension: /\.mdx?$/, @@ -24,8 +23,7 @@ const remoteImageURLs = [hasSetWebPrefix ? new URL(`${process.env.NEXT_PUBLIC_WE /** @type {import('next').NextConfig} */ const nextConfig = { - basePath, - assetPrefix, + basePath: process.env.NEXT_PUBLIC_BASE_PATH || '', webpack: (config, { dev, isServer }) => { if (dev) { config.plugins.push(codeInspectorPlugin({ bundler: 'webpack' })) diff --git a/web/utils/var-basePath.js b/web/utils/var-basePath.js deleted file mode 100644 index ff6dd505ea..0000000000 --- a/web/utils/var-basePath.js +++ /dev/null @@ -1,6 +0,0 @@ -// export basePath to next.config.js -// same as the one exported from var.ts -module.exports = { - basePath: process.env.NEXT_PUBLIC_BASE_PATH || '', - assetPrefix: '', -} diff --git a/web/utils/var.ts b/web/utils/var.ts index 4bbb7ca631..e3320a099d 100644 --- a/web/utils/var.ts +++ b/web/utils/var.ts @@ -118,7 +118,7 @@ export const getVars = (value: string) => { // Set the value of basePath // example: /dify -export const basePath = '' +export const basePath = process.env.NEXT_PUBLIC_BASE_PATH || '' export function getMarketplaceUrl(path: string, params?: Record) { const searchParams = new URLSearchParams({ source: encodeURIComponent(window.location.origin) }) From ffba341258b6ec96301c10279754481eff0db5bb Mon Sep 17 00:00:00 2001 From: willzhao Date: Mon, 1 Sep 2025 14:05:32 +0800 Subject: [PATCH 07/30] [CHORE]: remove redundant-cast (#24807) --- api/core/app/apps/advanced_chat/app_runner.py | 2 +- api/core/helper/encrypter.py | 2 +- api/core/model_manager.py | 18 ---------------- api/core/prompt/utils/prompt_message_util.py | 1 - api/core/provider_manager.py | 6 +++--- .../datasource/vdb/qdrant/qdrant_vector.py | 3 +-- api/core/rag/extractor/markdown_extractor.py | 4 ++-- api/core/rag/extractor/notion_extractor.py | 2 +- api/core/rag/extractor/pdf_extractor.py | 4 ++-- api/core/tools/tool_manager.py | 21 ++++++++----------- api/core/tools/utils/message_transformer.py | 5 ++--- .../tools/utils/model_invocation_utils.py | 19 +++++++---------- api/core/tools/workflow_as_tool/tool.py | 6 +++--- api/core/variables/variables.py | 4 ++-- .../workflow/graph_engine/graph_engine.py | 2 +- api/core/workflow/nodes/agent/agent_node.py | 5 ++--- .../workflow/nodes/document_extractor/node.py | 4 ++-- .../parameter_extractor_node.py | 2 +- .../question_classifier_node.py | 4 ++-- api/core/workflow/nodes/tool/tool_node.py | 4 ++-- api/core/workflow/workflow_entry.py | 3 +-- api/factories/file_factory.py | 3 +-- api/models/tools.py | 2 +- api/services/account_service.py | 6 +++--- api/services/annotation_service.py | 6 +++--- .../workflow/nodes/test_code.py | 6 ------ 26 files changed, 54 insertions(+), 90 deletions(-) diff --git a/api/core/app/apps/advanced_chat/app_runner.py b/api/core/app/apps/advanced_chat/app_runner.py index 3de2f5ca9e..8d256da9cb 100644 --- a/api/core/app/apps/advanced_chat/app_runner.py +++ b/api/core/app/apps/advanced_chat/app_runner.py @@ -140,7 +140,7 @@ class AdvancedChatAppRunner(WorkflowBasedAppRunner): environment_variables=self._workflow.environment_variables, # Based on the definition of `VariableUnion`, # `list[Variable]` can be safely used as `list[VariableUnion]` since they are compatible. - conversation_variables=cast(list[VariableUnion], conversation_variables), + conversation_variables=conversation_variables, ) # init graph diff --git a/api/core/helper/encrypter.py b/api/core/helper/encrypter.py index cac7e8e6e0..383a2dd57e 100644 --- a/api/core/helper/encrypter.py +++ b/api/core/helper/encrypter.py @@ -3,7 +3,7 @@ import base64 from libs import rsa -def obfuscated_token(token: str): +def obfuscated_token(token: str) -> str: if not token: return token if len(token) <= 8: diff --git a/api/core/model_manager.py b/api/core/model_manager.py index 51af3d1877..e567565548 100644 --- a/api/core/model_manager.py +++ b/api/core/model_manager.py @@ -158,8 +158,6 @@ class ModelInstance: """ if not isinstance(self.model_type_instance, LargeLanguageModel): raise Exception("Model type instance is not LargeLanguageModel") - - self.model_type_instance = cast(LargeLanguageModel, self.model_type_instance) return cast( Union[LLMResult, Generator], self._round_robin_invoke( @@ -188,8 +186,6 @@ class ModelInstance: """ if not isinstance(self.model_type_instance, LargeLanguageModel): raise Exception("Model type instance is not LargeLanguageModel") - - self.model_type_instance = cast(LargeLanguageModel, self.model_type_instance) return cast( int, self._round_robin_invoke( @@ -214,8 +210,6 @@ class ModelInstance: """ if not isinstance(self.model_type_instance, TextEmbeddingModel): raise Exception("Model type instance is not TextEmbeddingModel") - - self.model_type_instance = cast(TextEmbeddingModel, self.model_type_instance) return cast( TextEmbeddingResult, self._round_robin_invoke( @@ -237,8 +231,6 @@ class ModelInstance: """ if not isinstance(self.model_type_instance, TextEmbeddingModel): raise Exception("Model type instance is not TextEmbeddingModel") - - self.model_type_instance = cast(TextEmbeddingModel, self.model_type_instance) return cast( list[int], self._round_robin_invoke( @@ -269,8 +261,6 @@ class ModelInstance: """ if not isinstance(self.model_type_instance, RerankModel): raise Exception("Model type instance is not RerankModel") - - self.model_type_instance = cast(RerankModel, self.model_type_instance) return cast( RerankResult, self._round_robin_invoke( @@ -295,8 +285,6 @@ class ModelInstance: """ if not isinstance(self.model_type_instance, ModerationModel): raise Exception("Model type instance is not ModerationModel") - - self.model_type_instance = cast(ModerationModel, self.model_type_instance) return cast( bool, self._round_robin_invoke( @@ -318,8 +306,6 @@ class ModelInstance: """ if not isinstance(self.model_type_instance, Speech2TextModel): raise Exception("Model type instance is not Speech2TextModel") - - self.model_type_instance = cast(Speech2TextModel, self.model_type_instance) return cast( str, self._round_robin_invoke( @@ -343,8 +329,6 @@ class ModelInstance: """ if not isinstance(self.model_type_instance, TTSModel): raise Exception("Model type instance is not TTSModel") - - self.model_type_instance = cast(TTSModel, self.model_type_instance) return cast( Iterable[bytes], self._round_robin_invoke( @@ -404,8 +388,6 @@ class ModelInstance: """ if not isinstance(self.model_type_instance, TTSModel): raise Exception("Model type instance is not TTSModel") - - self.model_type_instance = cast(TTSModel, self.model_type_instance) return self.model_type_instance.get_tts_model_voices( model=self.model, credentials=self.credentials, language=language ) diff --git a/api/core/prompt/utils/prompt_message_util.py b/api/core/prompt/utils/prompt_message_util.py index 2f4e651461..cdc6ccc821 100644 --- a/api/core/prompt/utils/prompt_message_util.py +++ b/api/core/prompt/utils/prompt_message_util.py @@ -87,7 +87,6 @@ class PromptMessageUtil: if isinstance(prompt_message.content, list): for content in prompt_message.content: if content.type == PromptMessageContentType.TEXT: - content = cast(TextPromptMessageContent, content) text += content.data else: content = cast(ImagePromptMessageContent, content) diff --git a/api/core/provider_manager.py b/api/core/provider_manager.py index 28a4ce0778..cad0de6478 100644 --- a/api/core/provider_manager.py +++ b/api/core/provider_manager.py @@ -2,7 +2,7 @@ import contextlib import json from collections import defaultdict from json import JSONDecodeError -from typing import Any, Optional, cast +from typing import Any, Optional from sqlalchemy import select from sqlalchemy.exc import IntegrityError @@ -154,8 +154,8 @@ class ProviderManager: for provider_entity in provider_entities: # handle include, exclude if is_filtered( - include_set=cast(set[str], dify_config.POSITION_PROVIDER_INCLUDES_SET), - exclude_set=cast(set[str], dify_config.POSITION_PROVIDER_EXCLUDES_SET), + include_set=dify_config.POSITION_PROVIDER_INCLUDES_SET, + exclude_set=dify_config.POSITION_PROVIDER_EXCLUDES_SET, data=provider_entity, name_func=lambda x: x.provider, ): diff --git a/api/core/rag/datasource/vdb/qdrant/qdrant_vector.py b/api/core/rag/datasource/vdb/qdrant/qdrant_vector.py index fcf3a6d126..41ad5e57e6 100644 --- a/api/core/rag/datasource/vdb/qdrant/qdrant_vector.py +++ b/api/core/rag/datasource/vdb/qdrant/qdrant_vector.py @@ -3,7 +3,7 @@ import os import uuid from collections.abc import Generator, Iterable, Sequence from itertools import islice -from typing import TYPE_CHECKING, Any, Optional, Union, cast +from typing import TYPE_CHECKING, Any, Optional, Union import qdrant_client from flask import current_app @@ -426,7 +426,6 @@ class QdrantVector(BaseVector): def _reload_if_needed(self): if isinstance(self._client, QdrantLocal): - self._client = cast(QdrantLocal, self._client) self._client._load() @classmethod diff --git a/api/core/rag/extractor/markdown_extractor.py b/api/core/rag/extractor/markdown_extractor.py index c97765b1dc..3845392c8d 100644 --- a/api/core/rag/extractor/markdown_extractor.py +++ b/api/core/rag/extractor/markdown_extractor.py @@ -2,7 +2,7 @@ import re from pathlib import Path -from typing import Optional, cast +from typing import Optional from core.rag.extractor.extractor_base import BaseExtractor from core.rag.extractor.helpers import detect_file_encodings @@ -76,7 +76,7 @@ class MarkdownExtractor(BaseExtractor): markdown_tups.append((current_header, current_text)) markdown_tups = [ - (re.sub(r"#", "", cast(str, key)).strip() if key else None, re.sub(r"<.*?>", "", value)) + (re.sub(r"#", "", key).strip() if key else None, re.sub(r"<.*?>", "", value)) for key, value in markdown_tups ] diff --git a/api/core/rag/extractor/notion_extractor.py b/api/core/rag/extractor/notion_extractor.py index 17f4d1af2d..3d4b898c93 100644 --- a/api/core/rag/extractor/notion_extractor.py +++ b/api/core/rag/extractor/notion_extractor.py @@ -385,4 +385,4 @@ class NotionExtractor(BaseExtractor): f"No notion data source binding found for tenant {tenant_id} and notion workspace {notion_workspace_id}" ) - return cast(str, data_source_binding.access_token) + return data_source_binding.access_token diff --git a/api/core/rag/extractor/pdf_extractor.py b/api/core/rag/extractor/pdf_extractor.py index 7dfe2e357c..3c43f34104 100644 --- a/api/core/rag/extractor/pdf_extractor.py +++ b/api/core/rag/extractor/pdf_extractor.py @@ -2,7 +2,7 @@ import contextlib from collections.abc import Iterator -from typing import Optional, cast +from typing import Optional from core.rag.extractor.blob.blob import Blob from core.rag.extractor.extractor_base import BaseExtractor @@ -27,7 +27,7 @@ class PdfExtractor(BaseExtractor): plaintext_file_exists = False if self._file_cache_key: with contextlib.suppress(FileNotFoundError): - text = cast(bytes, storage.load(self._file_cache_key)).decode("utf-8") + text = storage.load(self._file_cache_key).decode("utf-8") plaintext_file_exists = True return [Document(page_content=text)] documents = list(self.load()) diff --git a/api/core/tools/tool_manager.py b/api/core/tools/tool_manager.py index 3454ec3489..b338a779ac 100644 --- a/api/core/tools/tool_manager.py +++ b/api/core/tools/tool_manager.py @@ -331,16 +331,13 @@ class ToolManager: if controller_tools is None or len(controller_tools) == 0: raise ToolProviderNotFoundError(f"workflow provider {provider_id} not found") - return cast( - WorkflowTool, - controller.get_tools(tenant_id=workflow_provider.tenant_id)[0].fork_tool_runtime( - runtime=ToolRuntime( - tenant_id=tenant_id, - credentials={}, - invoke_from=invoke_from, - tool_invoke_from=tool_invoke_from, - ) - ), + return controller.get_tools(tenant_id=workflow_provider.tenant_id)[0].fork_tool_runtime( + runtime=ToolRuntime( + tenant_id=tenant_id, + credentials={}, + invoke_from=invoke_from, + tool_invoke_from=tool_invoke_from, + ) ) elif provider_type == ToolProviderType.APP: raise NotImplementedError("app provider not implemented") @@ -648,8 +645,8 @@ class ToolManager: for provider in builtin_providers: # handle include, exclude if is_filtered( - include_set=cast(set[str], dify_config.POSITION_TOOL_INCLUDES_SET), - exclude_set=cast(set[str], dify_config.POSITION_TOOL_EXCLUDES_SET), + include_set=dify_config.POSITION_TOOL_INCLUDES_SET, + exclude_set=dify_config.POSITION_TOOL_EXCLUDES_SET, data=provider, name_func=lambda x: x.identity.name, ): diff --git a/api/core/tools/utils/message_transformer.py b/api/core/tools/utils/message_transformer.py index 8357dac0d7..bf075bd730 100644 --- a/api/core/tools/utils/message_transformer.py +++ b/api/core/tools/utils/message_transformer.py @@ -3,7 +3,7 @@ from collections.abc import Generator from datetime import date, datetime from decimal import Decimal from mimetypes import guess_extension -from typing import Optional, cast +from typing import Optional from uuid import UUID import numpy as np @@ -159,8 +159,7 @@ class ToolFileMessageTransformer: elif message.type == ToolInvokeMessage.MessageType.JSON: if isinstance(message.message, ToolInvokeMessage.JsonMessage): - json_msg = cast(ToolInvokeMessage.JsonMessage, message.message) - json_msg.json_object = safe_json_value(json_msg.json_object) + message.message.json_object = safe_json_value(message.message.json_object) yield message else: yield message diff --git a/api/core/tools/utils/model_invocation_utils.py b/api/core/tools/utils/model_invocation_utils.py index 3f59b3f472..251d914800 100644 --- a/api/core/tools/utils/model_invocation_utils.py +++ b/api/core/tools/utils/model_invocation_utils.py @@ -129,17 +129,14 @@ class ModelInvocationUtils: db.session.commit() try: - response: LLMResult = cast( - LLMResult, - model_instance.invoke_llm( - prompt_messages=prompt_messages, - model_parameters=model_parameters, - tools=[], - stop=[], - stream=False, - user=user_id, - callbacks=[], - ), + response: LLMResult = model_instance.invoke_llm( + prompt_messages=prompt_messages, + model_parameters=model_parameters, + tools=[], + stop=[], + stream=False, + user=user_id, + callbacks=[], ) except InvokeRateLimitError as e: raise InvokeModelError(f"Invoke rate limit error: {e}") diff --git a/api/core/tools/workflow_as_tool/tool.py b/api/core/tools/workflow_as_tool/tool.py index 1387df5973..ea219af684 100644 --- a/api/core/tools/workflow_as_tool/tool.py +++ b/api/core/tools/workflow_as_tool/tool.py @@ -1,7 +1,7 @@ import json import logging from collections.abc import Generator -from typing import Any, Optional, cast +from typing import Any, Optional from core.file import FILE_MODEL_IDENTITY, File, FileTransferMethod from core.tools.__base.tool import Tool @@ -204,14 +204,14 @@ class WorkflowTool(Tool): item = self._update_file_mapping(item) file = build_from_mapping( mapping=item, - tenant_id=str(cast(ToolRuntime, self.runtime).tenant_id), + tenant_id=str(self.runtime.tenant_id), ) files.append(file) elif isinstance(value, dict) and value.get("dify_model_identity") == FILE_MODEL_IDENTITY: value = self._update_file_mapping(value) file = build_from_mapping( mapping=value, - tenant_id=str(cast(ToolRuntime, self.runtime).tenant_id), + tenant_id=str(self.runtime.tenant_id), ) files.append(file) diff --git a/api/core/variables/variables.py b/api/core/variables/variables.py index 16c8116ac1..a994730cd5 100644 --- a/api/core/variables/variables.py +++ b/api/core/variables/variables.py @@ -1,5 +1,5 @@ from collections.abc import Sequence -from typing import Annotated, TypeAlias, cast +from typing import Annotated, TypeAlias from uuid import uuid4 from pydantic import Discriminator, Field, Tag @@ -86,7 +86,7 @@ class SecretVariable(StringVariable): @property def log(self) -> str: - return cast(str, encrypter.obfuscated_token(self.value)) + return encrypter.obfuscated_token(self.value) class NoneVariable(NoneSegment, Variable): diff --git a/api/core/workflow/graph_engine/graph_engine.py b/api/core/workflow/graph_engine/graph_engine.py index 03b920ccbb..188d0c475f 100644 --- a/api/core/workflow/graph_engine/graph_engine.py +++ b/api/core/workflow/graph_engine/graph_engine.py @@ -374,7 +374,7 @@ class GraphEngine: if len(sub_edge_mappings) == 0: continue - edge = cast(GraphEdge, sub_edge_mappings[0]) + edge = sub_edge_mappings[0] if edge.run_condition is None: logger.warning("Edge %s run condition is None", edge.target_node_id) continue diff --git a/api/core/workflow/nodes/agent/agent_node.py b/api/core/workflow/nodes/agent/agent_node.py index 144f036aa4..9e5d5e62b4 100644 --- a/api/core/workflow/nodes/agent/agent_node.py +++ b/api/core/workflow/nodes/agent/agent_node.py @@ -153,7 +153,7 @@ class AgentNode(BaseNode): messages=message_stream, tool_info={ "icon": self.agent_strategy_icon, - "agent_strategy": cast(AgentNodeData, self._node_data).agent_strategy_name, + "agent_strategy": self._node_data.agent_strategy_name, }, parameters_for_log=parameters_for_log, user_id=self.user_id, @@ -394,8 +394,7 @@ class AgentNode(BaseNode): current_plugin = next( plugin for plugin in plugins - if f"{plugin.plugin_id}/{plugin.name}" - == cast(AgentNodeData, self._node_data).agent_strategy_provider_name + if f"{plugin.plugin_id}/{plugin.name}" == self._node_data.agent_strategy_provider_name ) icon = current_plugin.declaration.icon except StopIteration: diff --git a/api/core/workflow/nodes/document_extractor/node.py b/api/core/workflow/nodes/document_extractor/node.py index b820999c3a..bb09b1a5dd 100644 --- a/api/core/workflow/nodes/document_extractor/node.py +++ b/api/core/workflow/nodes/document_extractor/node.py @@ -302,12 +302,12 @@ def _extract_text_from_yaml(file_content: bytes) -> str: encoding = "utf-8" yaml_data = yaml.safe_load_all(file_content.decode(encoding, errors="ignore")) - return cast(str, yaml.dump_all(yaml_data, allow_unicode=True, sort_keys=False)) + return yaml.dump_all(yaml_data, allow_unicode=True, sort_keys=False) except (UnicodeDecodeError, LookupError, yaml.YAMLError) as e: # If decoding fails, try with utf-8 as last resort try: yaml_data = yaml.safe_load_all(file_content.decode("utf-8", errors="ignore")) - return cast(str, yaml.dump_all(yaml_data, allow_unicode=True, sort_keys=False)) + return yaml.dump_all(yaml_data, allow_unicode=True, sort_keys=False) except (UnicodeDecodeError, yaml.YAMLError): raise TextExtractionError(f"Failed to decode or parse YAML file: {e}") from e diff --git a/api/core/workflow/nodes/parameter_extractor/parameter_extractor_node.py b/api/core/workflow/nodes/parameter_extractor/parameter_extractor_node.py index 3dcde5ad81..43edf7eac6 100644 --- a/api/core/workflow/nodes/parameter_extractor/parameter_extractor_node.py +++ b/api/core/workflow/nodes/parameter_extractor/parameter_extractor_node.py @@ -139,7 +139,7 @@ class ParameterExtractorNode(BaseNode): """ Run the node. """ - node_data = cast(ParameterExtractorNodeData, self._node_data) + node_data = self._node_data variable = self.graph_runtime_state.variable_pool.get(node_data.query) query = variable.text if variable else "" diff --git a/api/core/workflow/nodes/question_classifier/question_classifier_node.py b/api/core/workflow/nodes/question_classifier/question_classifier_node.py index 3e4984ecd5..ba4e55bb89 100644 --- a/api/core/workflow/nodes/question_classifier/question_classifier_node.py +++ b/api/core/workflow/nodes/question_classifier/question_classifier_node.py @@ -1,6 +1,6 @@ import json from collections.abc import Mapping, Sequence -from typing import TYPE_CHECKING, Any, Optional, cast +from typing import TYPE_CHECKING, Any, Optional from core.app.entities.app_invoke_entities import ModelConfigWithCredentialsEntity from core.memory.token_buffer_memory import TokenBufferMemory @@ -109,7 +109,7 @@ class QuestionClassifierNode(BaseNode): return "1" def _run(self): - node_data = cast(QuestionClassifierNodeData, self._node_data) + node_data = self._node_data variable_pool = self.graph_runtime_state.variable_pool # extract variables diff --git a/api/core/workflow/nodes/tool/tool_node.py b/api/core/workflow/nodes/tool/tool_node.py index 4c8e13de70..1a85c08b5b 100644 --- a/api/core/workflow/nodes/tool/tool_node.py +++ b/api/core/workflow/nodes/tool/tool_node.py @@ -1,5 +1,5 @@ from collections.abc import Generator, Mapping, Sequence -from typing import Any, Optional, cast +from typing import Any, Optional from sqlalchemy import select from sqlalchemy.orm import Session @@ -57,7 +57,7 @@ class ToolNode(BaseNode): Run the tool node """ - node_data = cast(ToolNodeData, self._node_data) + node_data = self._node_data # fetch tool icon tool_info = { diff --git a/api/core/workflow/workflow_entry.py b/api/core/workflow/workflow_entry.py index 801e36e272..e9b73df0f3 100644 --- a/api/core/workflow/workflow_entry.py +++ b/api/core/workflow/workflow_entry.py @@ -2,7 +2,7 @@ import logging import time import uuid from collections.abc import Generator, Mapping, Sequence -from typing import Any, Optional, cast +from typing import Any, Optional from configs import dify_config from core.app.apps.exc import GenerateTaskStoppedError @@ -261,7 +261,6 @@ class WorkflowEntry: environment_variables=[], ) - node_cls = cast(type[BaseNode], node_cls) # init workflow run state node: BaseNode = node_cls( id=str(uuid.uuid4()), diff --git a/api/factories/file_factory.py b/api/factories/file_factory.py index 0ea7d3ae1e..62e3bfa3ba 100644 --- a/api/factories/file_factory.py +++ b/api/factories/file_factory.py @@ -3,7 +3,7 @@ import os import urllib.parse import uuid from collections.abc import Callable, Mapping, Sequence -from typing import Any, cast +from typing import Any import httpx from sqlalchemy import select @@ -258,7 +258,6 @@ def _get_remote_file_info(url: str): mime_type = "" resp = ssrf_proxy.head(url, follow_redirects=True) - resp = cast(httpx.Response, resp) if resp.status_code == httpx.codes.OK: if content_disposition := resp.headers.get("Content-Disposition"): filename = str(content_disposition.split("filename=")[-1].strip('"')) diff --git a/api/models/tools.py b/api/models/tools.py index e0c9fa6ffc..d88d817374 100644 --- a/api/models/tools.py +++ b/api/models/tools.py @@ -308,7 +308,7 @@ class MCPToolProvider(Base): @property def decrypted_server_url(self) -> str: - return cast(str, encrypter.decrypt_token(self.tenant_id, self.server_url)) + return encrypter.decrypt_token(self.tenant_id, self.server_url) @property def masked_server_url(self) -> str: diff --git a/api/services/account_service.py b/api/services/account_service.py index 089e667166..50ce171ded 100644 --- a/api/services/account_service.py +++ b/api/services/account_service.py @@ -146,7 +146,7 @@ class AccountService: account.last_active_at = naive_utc_now() db.session.commit() - return cast(Account, account) + return account @staticmethod def get_account_jwt_token(account: Account) -> str: @@ -191,7 +191,7 @@ class AccountService: db.session.commit() - return cast(Account, account) + return account @staticmethod def update_account_password(account, password, new_password): @@ -1127,7 +1127,7 @@ class TenantService: def get_custom_config(tenant_id: str) -> dict: tenant = db.get_or_404(Tenant, tenant_id) - return cast(dict, tenant.custom_config_dict) + return tenant.custom_config_dict @staticmethod def is_owner(account: Account, tenant: Tenant) -> bool: diff --git a/api/services/annotation_service.py b/api/services/annotation_service.py index 6603063c22..9ee92bc2dc 100644 --- a/api/services/annotation_service.py +++ b/api/services/annotation_service.py @@ -1,5 +1,5 @@ import uuid -from typing import cast +from typing import Optional import pandas as pd from flask_login import current_user @@ -40,7 +40,7 @@ class AppAnnotationService: if not message: raise NotFound("Message Not Exists.") - annotation = message.annotation + annotation: Optional[MessageAnnotation] = message.annotation # save the message annotation if annotation: annotation.content = args["answer"] @@ -70,7 +70,7 @@ class AppAnnotationService: app_id, annotation_setting.collection_binding_id, ) - return cast(MessageAnnotation, annotation) + return annotation @classmethod def enable_app_annotation(cls, args: dict, app_id: str) -> dict: diff --git a/api/tests/integration_tests/workflow/nodes/test_code.py b/api/tests/integration_tests/workflow/nodes/test_code.py index 4f659c5e13..eb85d6118e 100644 --- a/api/tests/integration_tests/workflow/nodes/test_code.py +++ b/api/tests/integration_tests/workflow/nodes/test_code.py @@ -1,7 +1,6 @@ import time import uuid from os import getenv -from typing import cast import pytest @@ -13,7 +12,6 @@ from core.workflow.graph_engine.entities.graph import Graph from core.workflow.graph_engine.entities.graph_init_params import GraphInitParams from core.workflow.graph_engine.entities.graph_runtime_state import GraphRuntimeState from core.workflow.nodes.code.code_node import CodeNode -from core.workflow.nodes.code.entities import CodeNodeData from core.workflow.system_variable import SystemVariable from models.enums import UserFrom from models.workflow import WorkflowType @@ -238,8 +236,6 @@ def test_execute_code_output_validator_depth(): "object_validator": {"result": 1, "depth": {"depth": {"depth": 1}}}, } - node._node_data = cast(CodeNodeData, node._node_data) - # validate node._transform_result(result, node._node_data.outputs) @@ -334,8 +330,6 @@ def test_execute_code_output_object_list(): ] } - node._node_data = cast(CodeNodeData, node._node_data) - # validate node._transform_result(result, node._node_data.outputs) From 60d9d0584a6073ea4d0cc2925f74284be674748c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=A8=E4=B9=8B=E6=9C=AC=E6=BE=AA?= Date: Mon, 1 Sep 2025 14:28:21 +0800 Subject: [PATCH 08/30] refactor: migrate marketplace.py from requests to httpx (#24015) --- api/core/helper/marketplace.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/api/core/helper/marketplace.py b/api/core/helper/marketplace.py index fe3078923d..e837f2fd38 100644 --- a/api/core/helper/marketplace.py +++ b/api/core/helper/marketplace.py @@ -1,6 +1,6 @@ from collections.abc import Sequence -import requests +import httpx from yarl import URL from configs import dify_config @@ -23,7 +23,7 @@ def batch_fetch_plugin_manifests(plugin_ids: list[str]) -> Sequence[MarketplaceP return [] url = str(marketplace_api_url / "api/v1/plugins/batch") - response = requests.post(url, json={"plugin_ids": plugin_ids}) + response = httpx.post(url, json={"plugin_ids": plugin_ids}) response.raise_for_status() return [MarketplacePluginDeclaration(**plugin) for plugin in response.json()["data"]["plugins"]] @@ -36,7 +36,7 @@ def batch_fetch_plugin_manifests_ignore_deserialization_error( return [] url = str(marketplace_api_url / "api/v1/plugins/batch") - response = requests.post(url, json={"plugin_ids": plugin_ids}) + response = httpx.post(url, json={"plugin_ids": plugin_ids}) response.raise_for_status() result: list[MarketplacePluginDeclaration] = [] for plugin in response.json()["data"]["plugins"]: @@ -50,5 +50,5 @@ def batch_fetch_plugin_manifests_ignore_deserialization_error( 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}) + response = httpx.post(url, json={"unique_identifier": plugin_unique_identifier}) response.raise_for_status() From 1b401063e8d9bb44e5f0d4f9fc23fc99ddbee854 Mon Sep 17 00:00:00 2001 From: 17hz <0x149527@gmail.com> Date: Mon, 1 Sep 2025 14:45:44 +0800 Subject: [PATCH 09/30] chore: pnpx deprecation (#24868) --- web/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/package.json b/web/package.json index a422c7fd6c..528f5e468f 100644 --- a/web/package.json +++ b/web/package.json @@ -23,8 +23,8 @@ "build": "next build", "build:docker": "next build && node scripts/optimize-standalone.js", "start": "cp -r .next/static .next/standalone/.next/static && cp -r public .next/standalone/public && cross-env PORT=$npm_config_port HOSTNAME=$npm_config_host node .next/standalone/server.js", - "lint": "pnpx oxlint && pnpm eslint --cache --cache-location node_modules/.cache/eslint/.eslint-cache", - "lint-only-show-error": "pnpx oxlint && pnpm eslint --cache --cache-location node_modules/.cache/eslint/.eslint-cache --quiet", + "lint": "npx oxlint && pnpm eslint --cache --cache-location node_modules/.cache/eslint/.eslint-cache", + "lint-only-show-error": "npm oxlint && pnpm eslint --cache --cache-location node_modules/.cache/eslint/.eslint-cache --quiet", "fix": "eslint --fix .", "eslint-fix": "eslint --cache --cache-location node_modules/.cache/eslint/.eslint-cache --fix", "eslint-fix-only-show-error": "eslint --cache --cache-location node_modules/.cache/eslint/.eslint-cache --fix --quiet", From d5a521eef2b436f5a98aa21edb6844ee1c67b003 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=80=90=E5=B0=8F=E5=BF=83?= Date: Mon, 1 Sep 2025 14:48:56 +0800 Subject: [PATCH 10/30] fix: Fix database connection leak in EasyUIBasedGenerateTaskPipeline (#24815) --- .../task_pipeline/easy_ui_based_generate_task_pipeline.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/api/core/app/task_pipeline/easy_ui_based_generate_task_pipeline.py b/api/core/app/task_pipeline/easy_ui_based_generate_task_pipeline.py index 471118c8cb..e3b917067f 100644 --- a/api/core/app/task_pipeline/easy_ui_based_generate_task_pipeline.py +++ b/api/core/app/task_pipeline/easy_ui_based_generate_task_pipeline.py @@ -472,9 +472,10 @@ class EasyUIBasedGenerateTaskPipeline(BasedGenerateTaskPipeline): :param event: agent thought event :return: """ - agent_thought: Optional[MessageAgentThought] = ( - db.session.query(MessageAgentThought).where(MessageAgentThought.id == event.agent_thought_id).first() - ) + with Session(db.engine, expire_on_commit=False) as session: + agent_thought: Optional[MessageAgentThought] = ( + session.query(MessageAgentThought).where(MessageAgentThought.id == event.agent_thought_id).first() + ) if agent_thought: return AgentThoughtStreamResponse( From 414ee5197518adbd82c325eb151cc48667bcf0a5 Mon Sep 17 00:00:00 2001 From: Tianyi Jing Date: Mon, 1 Sep 2025 15:21:36 +0800 Subject: [PATCH 11/30] fix: add missing form for boolean types (#24812) Signed-off-by: jingfelix --- .../base/form/components/base/base-field.tsx | 19 +++++++++++++++++++ web/app/components/base/form/types.ts | 1 + 2 files changed, 20 insertions(+) diff --git a/web/app/components/base/form/components/base/base-field.tsx b/web/app/components/base/form/components/base/base-field.tsx index 4005bab6bc..35ca251a5b 100644 --- a/web/app/components/base/form/components/base/base-field.tsx +++ b/web/app/components/base/form/components/base/base-field.tsx @@ -12,6 +12,7 @@ import PureSelect from '@/app/components/base/select/pure' import type { FormSchema } from '@/app/components/base/form/types' import { FormTypeEnum } from '@/app/components/base/form/types' import { useRenderI18nObject } from '@/hooks/use-i18n' +import Radio from '@/app/components/base/radio' import RadioE from '@/app/components/base/radio/ui' export type BaseFieldProps = { @@ -102,6 +103,12 @@ const BaseField = ({ }) }, [values, show_on]) + const booleanRadioValue = useMemo(() => { + if (value === null || value === undefined) + return undefined + return value ? 1 : 0 + }, [value]) + if (!show) return null @@ -204,6 +211,18 @@ const BaseField = ({ ) } + { + formSchema.type === FormTypeEnum.boolean && ( + field.handleChange(val === 1)} + > + True + False + + ) + } { formSchema.url && ( Date: Mon, 1 Sep 2025 15:31:59 +0800 Subject: [PATCH 12/30] CI: add TS indentation check via esLint (#24810) --- .github/workflows/style.yml | 4 +- web/__tests__/check-i18n.test.ts | 2 +- web/__tests__/description-validation.test.tsx | 4 +- web/__tests__/document-list-sorting.test.tsx | 2 +- .../plugin-tool-workflow-error.test.tsx | 2 +- web/__tests__/real-browser-flicker.test.tsx | 2 +- .../workflow-parallel-limit.test.tsx | 4 +- .../svg-attribute-error-reproduction.spec.tsx | 4 +- .../account-page/AvatarWithEdit.tsx | 2 +- web/app/components/app-sidebar/basic.tsx | 4 +- web/app/components/app-sidebar/index.tsx | 4 +- .../sidebar-animation-issues.spec.tsx | 2 +- web/app/components/app/annotation/index.tsx | 2 +- .../config-var/config-modal/type-select.tsx | 10 +- .../params-config/config-content.tsx | 1 - .../configuration/debug/chat-user-input.tsx | 8 +- web/app/components/app/log/list.tsx | 124 +++++++++--------- web/app/components/app/overview/app-card.tsx | 2 +- .../app/overview/embedded/index.tsx | 8 +- .../app/overview/settings/index.tsx | 2 +- web/app/components/apps/list.tsx | 2 +- .../embedded-chatbot/inputs-form/content.tsx | 12 +- web/app/components/base/checkbox/index.tsx | 12 +- .../base/date-and-time-picker/utils/dayjs.ts | 2 +- .../base/form/form-scenarios/demo/index.tsx | 2 +- web/app/components/base/form/types.ts | 10 +- web/app/components/base/mermaid/index.tsx | 6 +- .../plugins/current-block/component.tsx | 6 +- .../plugins/error-message-block/component.tsx | 6 +- .../plugins/last-run-block/component.tsx | 6 +- web/app/components/base/select/index.tsx | 48 +++---- .../base/tag-management/selector.tsx | 2 +- web/app/components/base/toast/index.tsx | 2 +- .../common/retrieval-param-config/index.tsx | 1 - .../create/website/base/options-wrap.tsx | 1 - .../datasets/create/website/index.tsx | 3 +- .../website/jina-reader/base/options-wrap.tsx | 1 - .../detail/batch-modal/csv-uploader.tsx | 2 +- .../create/InfoPanel.tsx | 6 +- .../components/chunk-detail-modal.tsx | 4 +- .../hooks/use-edit-dataset-metadata.ts | 1 - .../actions/commands/registry.ts | 4 +- .../components/goto-anything/actions/index.ts | 4 +- web/app/components/goto-anything/index.tsx | 2 +- .../data-source-website/index.tsx | 1 - .../add-credential-in-load-balancing.tsx | 6 +- .../model-auth/authorized/index.tsx | 10 +- .../model-load-balancing-modal.tsx | 4 +- .../install-bundle/item/github-item.tsx | 3 - .../install-bundle/steps/install-multi.tsx | 6 - .../install-from-github/steps/loaded.tsx | 1 - .../steps/uploading.tsx | 1 - .../plugins/marketplace/context.tsx | 1 - .../plugins/plugin-auth/authorized/index.tsx | 28 ++-- .../hooks/use-plugin-auth-action.ts | 6 +- .../app-selector/index.tsx | 2 +- .../plugin-detail-panel/detail-header.tsx | 2 +- .../plugin-detail-panel/endpoint-modal.tsx | 4 +- .../multiple-tool-selector/index.tsx | 2 +- .../tool-selector/reasoning-config-form.tsx | 12 +- .../components/plugins/plugin-item/action.tsx | 1 - .../auto-update-setting/index.tsx | 24 ++-- .../auto-update-setting/utils.ts | 12 +- .../update-plugin/downgrade-warning.tsx | 2 +- .../update-plugin/from-market-place.tsx | 76 +++++------ .../components/tools/mcp/detail/content.tsx | 1 - .../components/tools/mcp/mcp-service-card.tsx | 6 +- .../components/tools/utils/to-form-schema.ts | 18 +-- .../workflow-app/hooks/use-workflow-init.ts | 1 - .../workflow/block-selector/all-tools.tsx | 1 - .../market-place-plugin/action.tsx | 1 - .../market-place-plugin/list.tsx | 1 - .../workflow/block-selector/tool/tool.tsx | 1 - .../datasets-detail-store/provider.tsx | 1 - .../workflow/header/header-in-restoring.tsx | 40 +++--- .../header/version-history-button.tsx | 20 +-- .../workflow/hooks-store/provider.tsx | 1 - .../hooks/use-inspect-vars-crud-common.ts | 58 ++++---- .../hooks/use-nodes-available-var-list.ts | 6 +- .../use-workflow-node-started.ts | 2 +- .../components/agent-strategy-selector.tsx | 2 +- .../nodes/_base/components/agent-strategy.tsx | 2 +- .../components/before-run-form/form-item.tsx | 8 +- .../components/input-support-select-var.tsx | 1 - .../mcp-tool-not-support-tooltip.tsx | 2 +- .../nodes/_base/components/variable/utils.ts | 4 +- .../_base/components/variable/var-list.tsx | 10 +- .../variable/var-reference-picker.tsx | 2 +- .../_base/components/workflow-panel/index.tsx | 4 +- .../workflow-panel/last-run/index.tsx | 10 +- .../nodes/_base/hooks/use-output-var-list.ts | 8 +- .../components/workflow/nodes/agent/panel.tsx | 8 +- .../nodes/agent/use-single-run-form-params.ts | 2 +- .../assigner/components/var-list/index.tsx | 2 +- .../nodes/http/hooks/use-key-value-list.ts | 2 - .../workflow/nodes/http/use-config.ts | 1 - .../components/metadata/metadata-trigger.tsx | 1 - .../nodes/knowledge-retrieval/use-config.ts | 3 - .../json-importer.tsx | 1 - .../nodes/parameter-extractor/use-config.ts | 1 - .../components/class-list.tsx | 8 +- .../nodes/question-classifier/use-config.ts | 2 - .../workflow/nodes/tool/use-config.ts | 1 - .../nodes/tool/use-single-run-form-params.ts | 2 +- .../workflow/operator/export-image.tsx | 4 +- .../workflow/panel/inputs-panel.tsx | 2 +- .../workflow/panel/workflow-preview.tsx | 2 +- .../workflow/selection-contextmenu.tsx | 2 +- .../workflow/variable-inspect/empty.tsx | 2 +- .../workflow/variable-inspect/index.tsx | 10 +- web/app/education-apply/hooks.ts | 44 +++---- web/app/install/installForm.tsx | 2 +- web/eslint.config.mjs | 8 +- web/i18n/en-US/workflow.ts | 2 +- web/package.json | 1 + web/service/base.ts | 46 +++---- web/service/use-plugins-auth.ts | 26 ++-- web/utils/navigation.ts | 8 +- 118 files changed, 457 insertions(+), 489 deletions(-) diff --git a/.github/workflows/style.yml b/.github/workflows/style.yml index b6c9131c08..9c79dbc57e 100644 --- a/.github/workflows/style.yml +++ b/.github/workflows/style.yml @@ -89,7 +89,9 @@ jobs: - name: Web style check if: steps.changed-files.outputs.any_changed == 'true' working-directory: ./web - run: pnpm run lint + run: | + pnpm run lint + pnpm run eslint docker-compose-template: name: Docker Compose Template diff --git a/web/__tests__/check-i18n.test.ts b/web/__tests__/check-i18n.test.ts index b4c4f1540d..b579f22d4b 100644 --- a/web/__tests__/check-i18n.test.ts +++ b/web/__tests__/check-i18n.test.ts @@ -621,7 +621,7 @@ export default translation && !trimmed.startsWith('//')) break } - else { + else { break } diff --git a/web/__tests__/description-validation.test.tsx b/web/__tests__/description-validation.test.tsx index 85263b035f..a78a4e632e 100644 --- a/web/__tests__/description-validation.test.tsx +++ b/web/__tests__/description-validation.test.tsx @@ -60,7 +60,7 @@ describe('Description Validation Logic', () => { try { validateDescriptionLength(invalidDescription) } - catch (error) { + catch (error) { expect((error as Error).message).toBe(expectedErrorMessage) } }) @@ -86,7 +86,7 @@ describe('Description Validation Logic', () => { expect(() => validateDescriptionLength(testDescription)).not.toThrow() expect(validateDescriptionLength(testDescription)).toBe(testDescription) } - else { + else { expect(() => validateDescriptionLength(testDescription)).toThrow( 'Description cannot exceed 400 characters.', ) diff --git a/web/__tests__/document-list-sorting.test.tsx b/web/__tests__/document-list-sorting.test.tsx index 1510dbec23..77c0bb60cf 100644 --- a/web/__tests__/document-list-sorting.test.tsx +++ b/web/__tests__/document-list-sorting.test.tsx @@ -39,7 +39,7 @@ describe('Document List Sorting', () => { const result = aValue.localeCompare(bValue) return order === 'asc' ? result : -result } - else { + else { const result = aValue - bValue return order === 'asc' ? result : -result } diff --git a/web/__tests__/plugin-tool-workflow-error.test.tsx b/web/__tests__/plugin-tool-workflow-error.test.tsx index 370052bc80..87bda8fa13 100644 --- a/web/__tests__/plugin-tool-workflow-error.test.tsx +++ b/web/__tests__/plugin-tool-workflow-error.test.tsx @@ -196,7 +196,7 @@ describe('Plugin Tool Workflow Integration', () => { const _pluginId = (tool.uniqueIdentifier as any).split(':')[0] }).toThrow() } - else { + else { // Valid tools should work fine expect(() => { const _pluginId = tool.uniqueIdentifier.split(':')[0] diff --git a/web/__tests__/real-browser-flicker.test.tsx b/web/__tests__/real-browser-flicker.test.tsx index cf3abd5f80..52bdf4777f 100644 --- a/web/__tests__/real-browser-flicker.test.tsx +++ b/web/__tests__/real-browser-flicker.test.tsx @@ -252,7 +252,7 @@ describe('Real Browser Environment Dark Mode Flicker Test', () => { if (hasStyleChange) console.log('⚠️ Style changes detected - this causes visible flicker') - else + else console.log('✅ No style changes detected') expect(timingData.length).toBeGreaterThan(1) diff --git a/web/__tests__/workflow-parallel-limit.test.tsx b/web/__tests__/workflow-parallel-limit.test.tsx index 0843122ab4..64e9d328f0 100644 --- a/web/__tests__/workflow-parallel-limit.test.tsx +++ b/web/__tests__/workflow-parallel-limit.test.tsx @@ -15,7 +15,7 @@ const originalEnv = process.env.NEXT_PUBLIC_MAX_PARALLEL_LIMIT function setupEnvironment(value?: string) { if (value) process.env.NEXT_PUBLIC_MAX_PARALLEL_LIMIT = value - else + else delete process.env.NEXT_PUBLIC_MAX_PARALLEL_LIMIT // Clear module cache to force re-evaluation @@ -25,7 +25,7 @@ function setupEnvironment(value?: string) { function restoreEnvironment() { if (originalEnv) process.env.NEXT_PUBLIC_MAX_PARALLEL_LIMIT = originalEnv - else + else delete process.env.NEXT_PUBLIC_MAX_PARALLEL_LIMIT jest.resetModules() diff --git a/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/tracing/__tests__/svg-attribute-error-reproduction.spec.tsx b/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/tracing/__tests__/svg-attribute-error-reproduction.spec.tsx index a3281be8eb..b1e915b2bf 100644 --- a/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/tracing/__tests__/svg-attribute-error-reproduction.spec.tsx +++ b/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/tracing/__tests__/svg-attribute-error-reproduction.spec.tsx @@ -47,7 +47,7 @@ describe('SVG Attribute Error Reproduction', () => { console.log(` ${index + 1}. ${error.substring(0, 100)}...`) }) } - else { + else { console.log('No inkscape errors found in this render') } @@ -150,7 +150,7 @@ describe('SVG Attribute Error Reproduction', () => { if (problematicKeys.length > 0) console.log(`🚨 PROBLEM: Still found problematic attributes: ${problematicKeys.join(', ')}`) - else + else console.log('✅ No problematic attributes found after normalization') }) }) diff --git a/web/app/account/(commonLayout)/account-page/AvatarWithEdit.tsx b/web/app/account/(commonLayout)/account-page/AvatarWithEdit.tsx index 0408d2ee34..5890c2ea92 100644 --- a/web/app/account/(commonLayout)/account-page/AvatarWithEdit.tsx +++ b/web/app/account/(commonLayout)/account-page/AvatarWithEdit.tsx @@ -106,7 +106,7 @@ const AvatarWithEdit = ({ onSave, ...props }: AvatarWithEditProps) => { onClick={() => { if (hoverArea === 'right' && !onAvatarError) setIsShowDeleteConfirm(true) - else + else setIsShowAvatarPicker(true) }} onMouseMove={(e) => { diff --git a/web/app/components/app-sidebar/basic.tsx b/web/app/components/app-sidebar/basic.tsx index 00357d6c27..77a965c03e 100644 --- a/web/app/components/app-sidebar/basic.tsx +++ b/web/app/components/app-sidebar/basic.tsx @@ -45,8 +45,8 @@ const ICON_MAP = { , dataset: , webapp:
- -
, + + , notion: , } diff --git a/web/app/components/app-sidebar/index.tsx b/web/app/components/app-sidebar/index.tsx index c3ff45d6a6..c60aa26f5d 100644 --- a/web/app/components/app-sidebar/index.tsx +++ b/web/app/components/app-sidebar/index.tsx @@ -62,12 +62,12 @@ const AppDetailNav = ({ title, desc, isExternal, icon, icon_background, navigati }, [appSidebarExpand, setAppSiderbarExpand]) if (inWorkflowCanvas && hideHeader) { - return ( + return (
) -} + } return (
{ })) }) - describe('Issue #1: Toggle Button Position Movement - FIXED', () => { + describe('Issue #1: Toggle Button Position Movement - FIXED', () => { it('should verify consistent padding prevents button position shift', () => { let expanded = false const handleToggle = () => { diff --git a/web/app/components/app/annotation/index.tsx b/web/app/components/app/annotation/index.tsx index bb2a95b0b5..afa8732701 100644 --- a/web/app/components/app/annotation/index.tsx +++ b/web/app/components/app/annotation/index.tsx @@ -84,7 +84,7 @@ const Annotation: FC = (props) => { setList(data as AnnotationItem[]) setTotal(total) } - finally { + finally { setIsLoading(false) } } diff --git a/web/app/components/app/configuration/config-var/config-modal/type-select.tsx b/web/app/components/app/configuration/config-var/config-modal/type-select.tsx index 3f6a01ed7c..beb7b03e37 100644 --- a/web/app/components/app/configuration/config-var/config-modal/type-select.tsx +++ b/web/app/components/app/configuration/config-var/config-modal/type-select.tsx @@ -52,13 +52,13 @@ const TypeSelector: FC = ({ >
- - {selectedItem?.name} - + > + {selectedItem?.name} +
{inputVarTypeToVarType(selectedItem?.value as InputVarType)} diff --git a/web/app/components/app/configuration/dataset-config/params-config/config-content.tsx b/web/app/components/app/configuration/dataset-config/params-config/config-content.tsx index 86025f68fa..cb61b927bc 100644 --- a/web/app/components/app/configuration/dataset-config/params-config/config-content.tsx +++ b/web/app/components/app/configuration/dataset-config/params-config/config-content.tsx @@ -175,7 +175,6 @@ const ConfigContent: FC = ({ ...datasetConfigs, reranking_enable: enable, }) - // eslint-disable-next-line react-hooks/exhaustive-deps }, [currentRerankModel, datasetConfigs, onChange]) return ( diff --git a/web/app/components/app/configuration/debug/chat-user-input.tsx b/web/app/components/app/configuration/debug/chat-user-input.tsx index ac07691ce4..b1161de075 100644 --- a/web/app/components/app/configuration/debug/chat-user-input.tsx +++ b/web/app/components/app/configuration/debug/chat-user-input.tsx @@ -57,10 +57,10 @@ const ChatUserInput = ({ >
{type !== 'checkbox' && ( -
-
{name || key}
- {!required && {t('workflow.panel.optional')}} -
+
+
{name || key}
+ {!required && {t('workflow.panel.optional')}} +
)}
{type === 'string' && ( diff --git a/web/app/components/app/log/list.tsx b/web/app/components/app/log/list.tsx index 67b8065745..b73d1f19de 100644 --- a/web/app/components/app/log/list.tsx +++ b/web/app/components/app/log/list.tsx @@ -112,72 +112,72 @@ const getFormattedChatList = (messages: ChatMessage[], conversationId: string, t const newChatList: IChatItem[] = [] try { messages.forEach((item: ChatMessage) => { - const questionFiles = item.message_files?.filter((file: any) => file.belongs_to === 'user') || [] - newChatList.push({ - id: `question-${item.id}`, - content: item.inputs.query || item.inputs.default_input || item.query, // text generation: item.inputs.query; chat: item.query - isAnswer: false, - message_files: getProcessedFilesFromResponse(questionFiles.map((item: any) => ({ ...item, related_id: item.id }))), - parentMessageId: item.parent_message_id || undefined, - }) + const questionFiles = item.message_files?.filter((file: any) => file.belongs_to === 'user') || [] + newChatList.push({ + id: `question-${item.id}`, + content: item.inputs.query || item.inputs.default_input || item.query, // text generation: item.inputs.query; chat: item.query + isAnswer: false, + message_files: getProcessedFilesFromResponse(questionFiles.map((item: any) => ({ ...item, related_id: item.id }))), + parentMessageId: item.parent_message_id || undefined, + }) - const answerFiles = item.message_files?.filter((file: any) => file.belongs_to === 'assistant') || [] - newChatList.push({ - id: item.id, - content: item.answer, - agent_thoughts: addFileInfos(item.agent_thoughts ? sortAgentSorts(item.agent_thoughts) : item.agent_thoughts, item.message_files), - feedback: item.feedbacks.find(item => item.from_source === 'user'), // user feedback - adminFeedback: item.feedbacks.find(item => item.from_source === 'admin'), // admin feedback - feedbackDisabled: false, - isAnswer: true, - message_files: getProcessedFilesFromResponse(answerFiles.map((item: any) => ({ ...item, related_id: item.id }))), - log: [ - ...item.message, - ...(item.message[item.message.length - 1]?.role !== 'assistant' - ? [ - { - role: 'assistant', - text: item.answer, - files: item.message_files?.filter((file: any) => file.belongs_to === 'assistant') || [], - }, - ] - : []), - ] as IChatItem['log'], - workflow_run_id: item.workflow_run_id, - conversationId, - input: { - inputs: item.inputs, - query: item.query, - }, - more: { - time: dayjs.unix(item.created_at).tz(timezone).format(format), - tokens: item.answer_tokens + item.message_tokens, - latency: item.provider_response_latency.toFixed(2), - }, - citation: item.metadata?.retriever_resources, - annotation: (() => { - if (item.annotation_hit_history) { - return { - id: item.annotation_hit_history.annotation_id, - authorName: item.annotation_hit_history.annotation_create_account?.name || 'N/A', - created_at: item.annotation_hit_history.created_at, + const answerFiles = item.message_files?.filter((file: any) => file.belongs_to === 'assistant') || [] + newChatList.push({ + id: item.id, + content: item.answer, + agent_thoughts: addFileInfos(item.agent_thoughts ? sortAgentSorts(item.agent_thoughts) : item.agent_thoughts, item.message_files), + feedback: item.feedbacks.find(item => item.from_source === 'user'), // user feedback + adminFeedback: item.feedbacks.find(item => item.from_source === 'admin'), // admin feedback + feedbackDisabled: false, + isAnswer: true, + message_files: getProcessedFilesFromResponse(answerFiles.map((item: any) => ({ ...item, related_id: item.id }))), + log: [ + ...item.message, + ...(item.message[item.message.length - 1]?.role !== 'assistant' + ? [ + { + role: 'assistant', + text: item.answer, + files: item.message_files?.filter((file: any) => file.belongs_to === 'assistant') || [], + }, + ] + : []), + ] as IChatItem['log'], + workflow_run_id: item.workflow_run_id, + conversationId, + input: { + inputs: item.inputs, + query: item.query, + }, + more: { + time: dayjs.unix(item.created_at).tz(timezone).format(format), + tokens: item.answer_tokens + item.message_tokens, + latency: item.provider_response_latency.toFixed(2), + }, + citation: item.metadata?.retriever_resources, + annotation: (() => { + if (item.annotation_hit_history) { + return { + id: item.annotation_hit_history.annotation_id, + authorName: item.annotation_hit_history.annotation_create_account?.name || 'N/A', + created_at: item.annotation_hit_history.created_at, + } } - } - if (item.annotation) { - return { - id: item.annotation.id, - authorName: item.annotation.account.name, - logAnnotation: item.annotation, - created_at: 0, + if (item.annotation) { + return { + id: item.annotation.id, + authorName: item.annotation.account.name, + logAnnotation: item.annotation, + created_at: 0, + } } - } - return undefined - })(), - parentMessageId: `question-${item.id}`, + return undefined + })(), + parentMessageId: `question-${item.id}`, + }) }) - }) return newChatList } @@ -503,7 +503,7 @@ function DetailPanel({ detail, onFeedback }: IDetailPanel) { setThreadChatItems(getThreadMessages(tree, newAllChatItems.at(-1)?.id)) } - catch (error) { + catch (error) { console.error(error) setHasMore(false) } @@ -522,7 +522,7 @@ function DetailPanel({ detail, onFeedback }: IDetailPanel) { if (outerDiv && outerDiv.scrollHeight > outerDiv.clientHeight) { scrollContainer = outerDiv } - else if (scrollableDiv && scrollableDiv.scrollHeight > scrollableDiv.clientHeight) { + else if (scrollableDiv && scrollableDiv.scrollHeight > scrollableDiv.clientHeight) { scrollContainer = scrollableDiv } else if (chatContainer && chatContainer.scrollHeight > chatContainer.clientHeight) { diff --git a/web/app/components/app/overview/app-card.tsx b/web/app/components/app/overview/app-card.tsx index 8713c8ef7b..c6df0ebfd9 100644 --- a/web/app/components/app/overview/app-card.tsx +++ b/web/app/components/app/overview/app-card.tsx @@ -167,7 +167,7 @@ function AppCard({ setAppDetail(res) setShowAccessControl(false) } - catch (error) { + catch (error) { console.error('Failed to fetch app detail:', error) } }, [appDetail, setAppDetail]) diff --git a/web/app/components/app/overview/embedded/index.tsx b/web/app/components/app/overview/embedded/index.tsx index cd25c4ca65..6eba993e1d 100644 --- a/web/app/components/app/overview/embedded/index.tsx +++ b/web/app/components/app/overview/embedded/index.tsx @@ -40,12 +40,12 @@ const OPTION_MAP = { `