From e6e76852d5fd630890a28c7e11a76e35bf32ce27 Mon Sep 17 00:00:00 2001 From: Bharat Ramanathan Date: Sat, 7 Jun 2025 20:36:23 +0530 Subject: [PATCH 1/5] Add support for W&B dedicated cloud instances in Weave tracing integration (#20765) Co-authored-by: crazywoola <427733928@qq.com> --- api/core/ops/entities/config_entity.py | 9 +++++++++ api/core/ops/ops_trace_manager.py | 2 +- api/core/ops/weave_trace/weave_trace.py | 15 ++++++++++++--- .../overview/tracing/provider-config-modal.tsx | 8 ++++++++ .../[appId]/overview/tracing/type.ts | 1 + 5 files changed, 31 insertions(+), 4 deletions(-) diff --git a/api/core/ops/entities/config_entity.py b/api/core/ops/entities/config_entity.py index f2d1bd305a..c988bf48d1 100644 --- a/api/core/ops/entities/config_entity.py +++ b/api/core/ops/entities/config_entity.py @@ -98,6 +98,7 @@ class WeaveConfig(BaseTracingConfig): entity: str | None = None project: str endpoint: str = "https://trace.wandb.ai" + host: str | None = None @field_validator("endpoint") @classmethod @@ -109,6 +110,14 @@ class WeaveConfig(BaseTracingConfig): return v + @field_validator("host") + @classmethod + def validate_host(cls, v, info: ValidationInfo): + if v is not None and v != "": + if not v.startswith(("https://", "http://")): + raise ValueError("host must start with https:// or http://") + return v + OPS_FILE_PATH = "ops_trace/" OPS_TRACE_FAILED_KEY = "FAILED_OPS_TRACE" diff --git a/api/core/ops/ops_trace_manager.py b/api/core/ops/ops_trace_manager.py index dc4cfc48db..e0dfe0c312 100644 --- a/api/core/ops/ops_trace_manager.py +++ b/api/core/ops/ops_trace_manager.py @@ -81,7 +81,7 @@ class OpsTraceProviderConfigMap(dict[str, dict[str, Any]]): return { "config_class": WeaveConfig, "secret_keys": ["api_key"], - "other_keys": ["project", "entity", "endpoint"], + "other_keys": ["project", "entity", "endpoint", "host"], "trace_instance": WeaveDataTrace, } diff --git a/api/core/ops/weave_trace/weave_trace.py b/api/core/ops/weave_trace/weave_trace.py index cfc8a505bb..3917348a91 100644 --- a/api/core/ops/weave_trace/weave_trace.py +++ b/api/core/ops/weave_trace/weave_trace.py @@ -40,9 +40,14 @@ class WeaveDataTrace(BaseTraceInstance): self.weave_api_key = weave_config.api_key self.project_name = weave_config.project self.entity = weave_config.entity + self.host = weave_config.host + + # Login with API key first, including host if provided + if self.host: + login_status = wandb.login(key=self.weave_api_key, verify=True, relogin=True, host=self.host) + else: + login_status = wandb.login(key=self.weave_api_key, verify=True, relogin=True) - # Login with API key first - login_status = wandb.login(key=self.weave_api_key, verify=True, relogin=True) if not login_status: logger.error("Failed to login to Weights & Biases with the provided API key") raise ValueError("Weave login failed") @@ -386,7 +391,11 @@ class WeaveDataTrace(BaseTraceInstance): def api_check(self): try: - login_status = wandb.login(key=self.weave_api_key, verify=True, relogin=True) + if self.host: + login_status = wandb.login(key=self.weave_api_key, verify=True, relogin=True, host=self.host) + else: + login_status = wandb.login(key=self.weave_api_key, verify=True, relogin=True) + if not login_status: raise ValueError("Weave login failed") else: diff --git a/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/tracing/provider-config-modal.tsx b/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/tracing/provider-config-modal.tsx index c0b52a9b10..b6c97add48 100644 --- a/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/tracing/provider-config-modal.tsx +++ b/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/tracing/provider-config-modal.tsx @@ -55,6 +55,7 @@ const weaveConfigTemplate = { entity: '', project: '', endpoint: '', + host: '', } const ProviderConfigModal: FC = ({ @@ -226,6 +227,13 @@ const ProviderConfigModal: FC = ({ onChange={handleConfigChange('endpoint')} placeholder={'https://trace.wandb.ai/'} /> + )} {type === TracingProvider.langSmith && ( diff --git a/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/tracing/type.ts b/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/tracing/type.ts index 386c58974e..ed468caf65 100644 --- a/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/tracing/type.ts +++ b/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/tracing/type.ts @@ -29,4 +29,5 @@ export type WeaveConfig = { entity: string project: string endpoint: string + host: string } From 65c7c01d90e5af44d4c9ff41689a855a7a82c772 Mon Sep 17 00:00:00 2001 From: yihong Date: Sat, 7 Jun 2025 23:06:46 +0800 Subject: [PATCH 2/5] fix: clean up two unreachable code (#20773) Signed-off-by: yihong0618 --- api/core/rag/datasource/vdb/oracle/oraclevector.py | 1 - .../utils/dataset_retriever/dataset_multi_retriever_tool.py | 2 -- 2 files changed, 3 deletions(-) diff --git a/api/core/rag/datasource/vdb/oracle/oraclevector.py b/api/core/rag/datasource/vdb/oracle/oraclevector.py index 6b9dd9c561..d1c8142b3d 100644 --- a/api/core/rag/datasource/vdb/oracle/oraclevector.py +++ b/api/core/rag/datasource/vdb/oracle/oraclevector.py @@ -303,7 +303,6 @@ class OracleVector(BaseVector): return docs else: return [Document(page_content="", metadata={})] - return [] def delete(self) -> None: with self._get_connection() as conn: diff --git a/api/core/tools/utils/dataset_retriever/dataset_multi_retriever_tool.py b/api/core/tools/utils/dataset_retriever/dataset_multi_retriever_tool.py index 93d3fcc49d..2cbc4b9821 100644 --- a/api/core/tools/utils/dataset_retriever/dataset_multi_retriever_tool.py +++ b/api/core/tools/utils/dataset_retriever/dataset_multi_retriever_tool.py @@ -153,8 +153,6 @@ class DatasetMultiRetrieverTool(DatasetRetrieverBaseTool): return str("\n".join(document_context_list)) return "" - raise RuntimeError("not segments found") - def _retriever( self, flask_app: Flask, From d6a8af03b4d2a56a30c6e42a2967347a6435c7ae Mon Sep 17 00:00:00 2001 From: NFish Date: Mon, 9 Jun 2025 15:44:49 +0800 Subject: [PATCH 3/5] Fix/add webapp no permission page (#20819) --- web/app/(shareLayout)/webapp-signin/page.tsx | 6 ++-- .../components/app/app-publisher/index.tsx | 6 ++-- web/app/components/base/app-unavailable.tsx | 2 +- .../base/chat/chat-with-history/index.tsx | 32 +++++++++++++++++-- .../base/chat/embedded-chatbot/index.tsx | 32 ++++++++++++++++--- .../share/text-generation/index.tsx | 23 +++++++++++-- web/app/components/share/utils.ts | 18 +---------- web/service/base.ts | 14 +++++--- 8 files changed, 95 insertions(+), 38 deletions(-) diff --git a/web/app/(shareLayout)/webapp-signin/page.tsx b/web/app/(shareLayout)/webapp-signin/page.tsx index c12fde38dd..07b7c88430 100644 --- a/web/app/(shareLayout)/webapp-signin/page.tsx +++ b/web/app/(shareLayout)/webapp-signin/page.tsx @@ -23,10 +23,12 @@ const WebSSOForm: FC = () => { const redirectUrl = searchParams.get('redirect_url') const tokenFromUrl = searchParams.get('web_sso_token') const message = searchParams.get('message') + const code = searchParams.get('code') const getSigninUrl = useCallback(() => { const params = new URLSearchParams(searchParams) params.delete('message') + params.delete('code') return `/webapp-signin?${params.toString()}` }, [searchParams]) @@ -85,8 +87,8 @@ const WebSSOForm: FC = () => { if (message) { return
- - {t('share.login.backToHome')} + + {code === '403' ? t('common.userProfile.logout') : t('share.login.backToHome')}
} if (!redirectUrl) { diff --git a/web/app/components/app/app-publisher/index.tsx b/web/app/components/app/app-publisher/index.tsx index 5825bb72ee..1485964198 100644 --- a/web/app/components/app/app-publisher/index.tsx +++ b/web/app/components/app/app-publisher/index.tsx @@ -278,7 +278,7 @@ const AppPublisher = ({ onClick={() => { setShowAppAccessControl(true) }}> -
+
{appDetail?.access_mode === AccessMode.ORGANIZATION && <> @@ -288,7 +288,9 @@ const AppPublisher = ({ {appDetail?.access_mode === AccessMode.SPECIFIC_GROUPS_MEMBERS && <> -

{t('app.accessControlDialog.accessItems.specific')}

+
+ {t('app.accessControlDialog.accessItems.specific')} +
} {appDetail?.access_mode === AccessMode.PUBLIC diff --git a/web/app/components/base/app-unavailable.tsx b/web/app/components/base/app-unavailable.tsx index 928c850262..c501d36118 100644 --- a/web/app/components/base/app-unavailable.tsx +++ b/web/app/components/base/app-unavailable.tsx @@ -21,7 +21,7 @@ const AppUnavailable: FC = ({ return (
-

{code}

diff --git a/web/app/components/base/chat/chat-with-history/index.tsx b/web/app/components/base/chat/chat-with-history/index.tsx index 1fd1383196..fe8e7b430d 100644 --- a/web/app/components/base/chat/chat-with-history/index.tsx +++ b/web/app/components/base/chat/chat-with-history/index.tsx @@ -1,5 +1,7 @@ +'use client' import type { FC } from 'react' import { + useCallback, useEffect, useState, } from 'react' @@ -17,10 +19,12 @@ import ChatWrapper from './chat-wrapper' import type { InstalledApp } from '@/models/explore' import Loading from '@/app/components/base/loading' import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints' -import { checkOrSetAccessToken } from '@/app/components/share/utils' +import { checkOrSetAccessToken, removeAccessToken } from '@/app/components/share/utils' import AppUnavailable from '@/app/components/base/app-unavailable' import cn from '@/utils/classnames' import useDocumentTitle from '@/hooks/use-document-title' +import { useTranslation } from 'react-i18next' +import { usePathname, useRouter, useSearchParams } from 'next/navigation' type ChatWithHistoryProps = { className?: string @@ -38,6 +42,7 @@ const ChatWithHistory: FC = ({ isMobile, themeBuilder, sidebarCollapseState, + isInstalledApp, } = useChatWithHistoryContext() const isSidebarCollapsed = sidebarCollapseState const customConfig = appData?.custom_config @@ -51,13 +56,34 @@ const ChatWithHistory: FC = ({ useDocumentTitle(site?.title || 'Chat') + const { t } = useTranslation() + const searchParams = useSearchParams() + const router = useRouter() + const pathname = usePathname() + const getSigninUrl = useCallback(() => { + const params = new URLSearchParams(searchParams) + params.delete('message') + params.set('redirect_url', pathname) + return `/webapp-signin?${params.toString()}` + }, [searchParams, pathname]) + + const backToHome = useCallback(() => { + removeAccessToken() + const url = getSigninUrl() + router.replace(url) + }, [getSigninUrl, router]) + if (appInfoLoading) { return ( ) } - if (!userCanAccess) - return + if (!userCanAccess) { + return
+ + {!isInstalledApp && {t('common.userProfile.logout')}} +
+ } if (appInfoError) { return ( diff --git a/web/app/components/base/chat/embedded-chatbot/index.tsx b/web/app/components/base/chat/embedded-chatbot/index.tsx index 002d142542..c54afd78ea 100644 --- a/web/app/components/base/chat/embedded-chatbot/index.tsx +++ b/web/app/components/base/chat/embedded-chatbot/index.tsx @@ -1,4 +1,6 @@ +'use client' import { + useCallback, useEffect, useState, } from 'react' @@ -12,7 +14,7 @@ import { useEmbeddedChatbot } from './hooks' import { isDify } from './utils' import { useThemeContext } from './theme/theme-context' import { CssTransform } from './theme/utils' -import { checkOrSetAccessToken } from '@/app/components/share/utils' +import { checkOrSetAccessToken, removeAccessToken } from '@/app/components/share/utils' import AppUnavailable from '@/app/components/base/app-unavailable' import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints' import Loading from '@/app/components/base/loading' @@ -23,6 +25,7 @@ import DifyLogo from '@/app/components/base/logo/dify-logo' import cn from '@/utils/classnames' import useDocumentTitle from '@/hooks/use-document-title' import { useGlobalPublicStore } from '@/context/global-public-context' +import { usePathname, useRouter, useSearchParams } from 'next/navigation' const Chatbot = () => { const { @@ -36,6 +39,7 @@ const Chatbot = () => { chatShouldReloadKey, handleNewConversation, themeBuilder, + isInstalledApp, } = useEmbeddedChatbotContext() const { t } = useTranslation() const systemFeatures = useGlobalPublicStore(s => s.systemFeatures) @@ -51,6 +55,22 @@ const Chatbot = () => { useDocumentTitle(site?.title || 'Chat') + const searchParams = useSearchParams() + const router = useRouter() + const pathname = usePathname() + const getSigninUrl = useCallback(() => { + const params = new URLSearchParams(searchParams) + params.delete('message') + params.set('redirect_url', pathname) + return `/webapp-signin?${params.toString()}` + }, [searchParams, pathname]) + + const backToHome = useCallback(() => { + removeAccessToken() + const url = getSigninUrl() + router.replace(url) + }, [getSigninUrl, router]) + if (appInfoLoading) { return ( <> @@ -66,8 +86,12 @@ const Chatbot = () => { ) } - if (!userCanAccess) - return + if (!userCanAccess) { + return
+ + {!isInstalledApp && {t('common.userProfile.logout')}} +
+ } if (appInfoError) { return ( @@ -141,7 +165,6 @@ const EmbeddedChatbotWrapper = () => { appInfoError, appInfoLoading, appData, - accessMode, userCanAccess, appParams, appMeta, @@ -176,7 +199,6 @@ const EmbeddedChatbotWrapper = () => { return = ({
) + const getSigninUrl = useCallback(() => { + const params = new URLSearchParams(searchParams) + params.delete('message') + params.set('redirect_url', pathname) + return `/webapp-signin?${params.toString()}` + }, [searchParams, pathname]) + + const backToHome = useCallback(() => { + removeAccessToken() + const url = getSigninUrl() + router.replace(url) + }, [getSigninUrl, router]) + if (!appId || !siteInfo || !promptConfig || (systemFeatures.webapp_auth.enabled && (isGettingAccessMode || isCheckingPermission))) { return (
) } - if (systemFeatures.webapp_auth.enabled && !userCanAccessResult?.result) - return + if (systemFeatures.webapp_auth.enabled && !userCanAccessResult?.result) { + return
+ + {!isInstalledApp && {t('common.userProfile.logout')}} +
+ } return (
{ - const sharedToken = globalThis.location.pathname.split('/').slice(-1)[0] - - const accessToken = localStorage.getItem('token') || JSON.stringify(getInitialTokenV2()) - let accessTokenJson = getInitialTokenV2() - try { - accessTokenJson = JSON.parse(accessToken) - if (isTokenV1(accessTokenJson)) - accessTokenJson = getInitialTokenV2() - } - catch { - - } - - localStorage.removeItem(CONVERSATION_ID_INFO) + localStorage.removeItem('token') localStorage.removeItem('webapp_access_token') - - delete accessTokenJson[sharedToken] - localStorage.setItem('token', JSON.stringify(accessTokenJson)) } diff --git a/web/service/base.ts b/web/service/base.ts index c3cafe600b..ba398c07a6 100644 --- a/web/service/base.ts +++ b/web/service/base.ts @@ -108,12 +108,13 @@ function unicodeToChar(text: string) { }) } -function requiredWebSSOLogin(message?: string) { - removeAccessToken() +function requiredWebSSOLogin(message?: string, code?: number) { const params = new URLSearchParams() params.append('redirect_url', globalThis.location.pathname) if (message) params.append('message', message) + if (code) + params.append('code', String(code)) globalThis.location.href = `/webapp-signin?${params.toString()}` } @@ -403,10 +404,12 @@ export const ssePost = async ( res.json().then((data: any) => { if (isPublicAPI) { if (data.code === 'web_app_access_denied') - requiredWebSSOLogin(data.message) + requiredWebSSOLogin(data.message, 403) - if (data.code === 'web_sso_auth_required') + if (data.code === 'web_sso_auth_required') { + removeAccessToken() requiredWebSSOLogin() + } if (data.code === 'unauthorized') { removeAccessToken() @@ -484,10 +487,11 @@ export const request = async(url: string, options = {}, otherOptions?: IOther const { code, message } = errRespData // webapp sso if (code === 'web_app_access_denied') { - requiredWebSSOLogin(message) + requiredWebSSOLogin(message, 403) return Promise.reject(err) } if (code === 'web_sso_auth_required') { + removeAccessToken() requiredWebSSOLogin() return Promise.reject(err) } From ab62a9662c9d56048d6414339c951fd9182bce9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9D=9E=E6=B3=95=E6=93=8D=E4=BD=9C?= Date: Mon, 9 Jun 2025 16:09:27 +0800 Subject: [PATCH 4/5] fix: some dark mode display incorrect (#20788) --- web/app/components/base/chat/chat/chat-input-area/index.tsx | 2 +- web/app/components/base/markdown-blocks/think-block.tsx | 4 ++-- .../nodes/_base/components/variable/var-reference-vars.tsx | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/web/app/components/base/chat/chat/chat-input-area/index.tsx b/web/app/components/base/chat/chat/chat-input-area/index.tsx index 52490e4024..cbfa3168e9 100644 --- a/web/app/components/base/chat/chat/chat-input-area/index.tsx +++ b/web/app/components/base/chat/chat/chat-input-area/index.tsx @@ -192,7 +192,7 @@ const ChatInputArea = ({