better define

This commit is contained in:
Stephen Zhou
2026-02-06 18:17:47 +08:00
parent d07da73fab
commit c71e89f83a
9 changed files with 152 additions and 80 deletions

View File

@@ -13,8 +13,8 @@ type Props = {
}
const maxTopK = (() => {
const configValue = Number.parseInt(env.NEXT_PUBLIC_TOP_K_MAX_VALUE || '', 10)
if (configValue && !isNaN(configValue))
const configValue = env.NEXT_PUBLIC_TOP_K_MAX_VALUE
if (configValue && !Number.isNaN(configValue))
return configValue
return 10
})()

View File

@@ -47,7 +47,7 @@ export const DelimiterInput: FC<InputProps & { tooltip?: string }> = (props) =>
}
export const MaxLengthInput: FC<InputNumberProps> = (props) => {
const maxValue = Number.parseInt(env.NEXT_PUBLIC_INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH || '4000', 10)
const maxValue = env.NEXT_PUBLIC_INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH ?? 4000
const { t } = useTranslation()
return (

View File

@@ -9,10 +9,7 @@ import unescape from './unescape'
export const DEFAULT_SEGMENT_IDENTIFIER = '\\n\\n'
export const DEFAULT_MAXIMUM_CHUNK_LENGTH = 1024
export const DEFAULT_OVERLAP = 50
export const MAXIMUM_CHUNK_TOKEN_LENGTH = Number.parseInt(
env.NEXT_PUBLIC_INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH || '4000',
10,
)
export const MAXIMUM_CHUNK_TOKEN_LENGTH = env.NEXT_PUBLIC_INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH ?? 4000
export type ParentChildConfig = {
chunkForContext: ParentMode

View File

@@ -17,8 +17,8 @@ export type TopKAndScoreThresholdProps = {
}
const maxTopK = (() => {
const configValue = Number.parseInt(env.NEXT_PUBLIC_TOP_K_MAX_VALUE || '', 10)
if (configValue && !isNaN(configValue))
const configValue = env.NEXT_PUBLIC_TOP_K_MAX_VALUE
if (configValue && !Number.isNaN(configValue))
return configValue
return 10
})()

View File

@@ -7,23 +7,18 @@ import { AgentStrategy } from '@/types/app'
import pkg from '../package.json'
const getBooleanConfig = (
envVar: string | undefined,
envVar: boolean | undefined,
defaultValue: boolean = true,
) => {
if (envVar !== undefined && envVar !== '')
return envVar === 'true'
return defaultValue
return envVar ?? defaultValue
}
const getNumberConfig = (
envVar: string | undefined,
envVar: number | undefined,
defaultValue: number,
) => {
if (envVar) {
const parsed = Number.parseInt(envVar)
if (!Number.isNaN(parsed) && parsed > 0)
return parsed
}
if (typeof envVar === 'number' && Number.isFinite(envVar) && envVar > 0)
return envVar
return defaultValue
}
@@ -317,7 +312,7 @@ export const VAR_REGEX
export const resetReg = () => (VAR_REGEX.lastIndex = 0)
export const DISABLE_UPLOAD_IMAGE_AS_ICON
= env.NEXT_PUBLIC_DISABLE_UPLOAD_IMAGE_AS_ICON === 'true'
= getBooleanConfig(env.NEXT_PUBLIC_DISABLE_UPLOAD_IMAGE_AS_ICON, false)
export const GITHUB_ACCESS_TOKEN
= env.NEXT_PUBLIC_GITHUB_ACCESS_TOKEN || ''
@@ -405,7 +400,7 @@ export const ZENDESK_FIELD_IDS = {
}
export const APP_VERSION = pkg.version
export const IS_MARKETPLACE = env.NEXT_PUBLIC_IS_MARKETPLACE === 'true'
export const IS_MARKETPLACE = getBooleanConfig(env.NEXT_PUBLIC_IS_MARKETPLACE, false)
export const RAG_PIPELINE_PREVIEW_CHUNK_NUM = 20

View File

@@ -8,59 +8,149 @@ import { ObjectFromEntries, ObjectKeys } from './utils/object'
const CLIENT_ENV_PREFIX = 'NEXT_PUBLIC_'
type ClientSchema = Record<`${typeof CLIENT_ENV_PREFIX}${string}`, z.ZodType>
const optionalString = z.string().optional()
const coercedBoolean = z.string().transform(s => s !== 'false' && s !== '0')
const coercedNumber = z.coerce.number().int().nonnegative()
/// keep-sorted
const clientSchema = {
NEXT_PUBLIC_ALLOW_EMBED: optionalString,
NEXT_PUBLIC_ALLOW_UNSAFE_DATA_SCHEME: optionalString,
NEXT_PUBLIC_AMPLITUDE_API_KEY: optionalString,
NEXT_PUBLIC_API_PREFIX: optionalString,
NEXT_PUBLIC_BASE_PATH: optionalString,
NEXT_PUBLIC_BATCH_CONCURRENCY: optionalString,
NEXT_PUBLIC_COOKIE_DOMAIN: optionalString,
NEXT_PUBLIC_CSP_WHITELIST: optionalString,
NEXT_PUBLIC_DEPLOY_ENV: optionalString,
NEXT_PUBLIC_DISABLE_UPLOAD_IMAGE_AS_ICON: optionalString,
NEXT_PUBLIC_EDITION: optionalString,
NEXT_PUBLIC_ENABLE_SINGLE_DOLLAR_LATEX: optionalString,
NEXT_PUBLIC_ENABLE_WEBSITE_FIRECRAWL: optionalString,
NEXT_PUBLIC_ENABLE_WEBSITE_JINAREADER: optionalString,
NEXT_PUBLIC_ENABLE_WEBSITE_WATERCRAWL: optionalString,
NEXT_PUBLIC_GITHUB_ACCESS_TOKEN: optionalString,
NEXT_PUBLIC_INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH: optionalString,
NEXT_PUBLIC_IS_MARKETPLACE: optionalString,
NEXT_PUBLIC_LOOP_NODE_MAX_COUNT: optionalString,
NEXT_PUBLIC_MAINTENANCE_NOTICE: optionalString,
NEXT_PUBLIC_MARKETPLACE_API_PREFIX: optionalString,
NEXT_PUBLIC_MARKETPLACE_URL_PREFIX: optionalString,
NEXT_PUBLIC_MAX_ITERATIONS_NUM: optionalString,
NEXT_PUBLIC_MAX_PARALLEL_LIMIT: optionalString,
NEXT_PUBLIC_MAX_TOOLS_NUM: optionalString,
NEXT_PUBLIC_MAX_TREE_DEPTH: optionalString,
NEXT_PUBLIC_PUBLIC_API_PREFIX: optionalString,
NEXT_PUBLIC_SENTRY_DSN: optionalString,
NEXT_PUBLIC_SITE_ABOUT: optionalString,
NEXT_PUBLIC_SUPPORT_MAIL_LOGIN: optionalString,
NEXT_PUBLIC_TEXT_GENERATION_TIMEOUT_MS: optionalString,
NEXT_PUBLIC_TOP_K_MAX_VALUE: optionalString,
NEXT_PUBLIC_UPLOAD_IMAGE_AS_ICON: optionalString,
NEXT_PUBLIC_WEB_PREFIX: optionalString,
NEXT_PUBLIC_ZENDESK_FIELD_ID_EMAIL: optionalString,
NEXT_PUBLIC_ZENDESK_FIELD_ID_ENVIRONMENT: optionalString,
NEXT_PUBLIC_ZENDESK_FIELD_ID_PLAN: optionalString,
NEXT_PUBLIC_ZENDESK_FIELD_ID_VERSION: optionalString,
NEXT_PUBLIC_ZENDESK_FIELD_ID_WORKSPACE_ID: optionalString,
NEXT_PUBLIC_ZENDESK_WIDGET_KEY: optionalString,
/**
* Default is not allow to embed into iframe to prevent Clickjacking: https://owasp.org/www-community/attacks/Clickjacking
*/
NEXT_PUBLIC_ALLOW_EMBED: coercedBoolean.default(false),
/**
* Allow rendering unsafe URLs which have "data:" scheme.
*/
NEXT_PUBLIC_ALLOW_UNSAFE_DATA_SCHEME: coercedBoolean.default(false),
/**
* The API key of amplitude
*/
NEXT_PUBLIC_AMPLITUDE_API_KEY: z.string().optional(),
/**
* The base URL of console application, refers to the Console base URL of WEB service if console domain is
* different from api or web app domain.
* example: http://cloud.dify.ai/console/api
*/
NEXT_PUBLIC_API_PREFIX: z.string().regex(/^(https?:\/\/|\/).*/).optional(),
/**
* The base path for the application
*/
NEXT_PUBLIC_BASE_PATH: z.string().regex(/^\/.*$/).optional(),
/**
* number of concurrency
*/
NEXT_PUBLIC_BATCH_CONCURRENCY: coercedNumber.default(5),
/**
* When the frontend and backend run on different subdomains, set NEXT_PUBLIC_COOKIE_DOMAIN=1.
*/
NEXT_PUBLIC_COOKIE_DOMAIN: z.string().optional(),
/**
* CSP https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP
*/
NEXT_PUBLIC_CSP_WHITELIST: z.string().optional(),
/**
* For production release, change this to PRODUCTION
*/
NEXT_PUBLIC_DEPLOY_ENV: z.enum(['DEVELOPMENT', 'PRODUCTION', 'TESTING']).optional(),
NEXT_PUBLIC_DISABLE_UPLOAD_IMAGE_AS_ICON: coercedBoolean.default(false),
/**
* The deployment edition, SELF_HOSTED
*/
NEXT_PUBLIC_EDITION: z.enum(['SELF_HOSTED', 'CLOUD']).default('SELF_HOSTED'),
/**
* Enable inline LaTeX rendering with single dollar signs ($...$)
* Default is false for security reasons to prevent conflicts with regular text
*/
NEXT_PUBLIC_ENABLE_SINGLE_DOLLAR_LATEX: coercedBoolean.default(false),
NEXT_PUBLIC_ENABLE_WEBSITE_FIRECRAWL: coercedBoolean.default(true),
NEXT_PUBLIC_ENABLE_WEBSITE_JINAREADER: coercedBoolean.default(true),
NEXT_PUBLIC_ENABLE_WEBSITE_WATERCRAWL: coercedBoolean.default(false),
/**
* Github Access Token, used for invoking Github API
*/
NEXT_PUBLIC_GITHUB_ACCESS_TOKEN: z.string().optional(),
/**
* The maximum number of tokens for segmentation
*/
NEXT_PUBLIC_INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH: coercedNumber.default(4000),
NEXT_PUBLIC_IS_MARKETPLACE: coercedBoolean.default(false),
/**
* Maximum loop count in the workflow
*/
NEXT_PUBLIC_LOOP_NODE_MAX_COUNT: coercedNumber.default(100),
NEXT_PUBLIC_MAINTENANCE_NOTICE: z.string().optional(),
/**
* The API PREFIX for MARKETPLACE
*/
NEXT_PUBLIC_MARKETPLACE_API_PREFIX: z.string().regex(/^(https?:\/\/|\/).*/).optional(),
/**
* The URL for MARKETPLACE
*/
NEXT_PUBLIC_MARKETPLACE_URL_PREFIX: z.string().url().optional(),
/**
* The maximum number of iterations for agent setting
*/
NEXT_PUBLIC_MAX_ITERATIONS_NUM: coercedNumber.default(99),
/**
* Maximum number of Parallelism branches in the workflow
*/
NEXT_PUBLIC_MAX_PARALLEL_LIMIT: coercedNumber.default(10),
/**
* Maximum number of tools in the agent/workflow
*/
NEXT_PUBLIC_MAX_TOOLS_NUM: coercedNumber.default(10),
/**
* The maximum number of tree node depth for workflow
*/
NEXT_PUBLIC_MAX_TREE_DEPTH: coercedNumber.default(50),
/**
* The URL for Web APP, refers to the Web App base URL of WEB service if web app domain is different from
* console or api domain.
* example: http://udify.app/api
*/
NEXT_PUBLIC_PUBLIC_API_PREFIX: z.string().regex(/^(https?:\/\/|\/).*/).optional(),
/**
* SENTRY
*/
NEXT_PUBLIC_SENTRY_DSN: z.string().optional(),
NEXT_PUBLIC_SITE_ABOUT: z.string().optional(),
NEXT_PUBLIC_SUPPORT_MAIL_LOGIN: coercedBoolean.default(false),
/**
* The timeout for the text generation in millisecond
*/
NEXT_PUBLIC_TEXT_GENERATION_TIMEOUT_MS: coercedNumber.default(60000),
/**
* The maximum number of top-k value for RAG.
*/
NEXT_PUBLIC_TOP_K_MAX_VALUE: coercedNumber.default(10),
/**
* Disable Upload Image as WebApp icon default is false
*/
NEXT_PUBLIC_UPLOAD_IMAGE_AS_ICON: coercedBoolean.default(false),
NEXT_PUBLIC_WEB_PREFIX: z.url().optional(),
NEXT_PUBLIC_ZENDESK_FIELD_ID_EMAIL: z.string().optional(),
NEXT_PUBLIC_ZENDESK_FIELD_ID_ENVIRONMENT: z.string().optional(),
NEXT_PUBLIC_ZENDESK_FIELD_ID_PLAN: z.string().optional(),
NEXT_PUBLIC_ZENDESK_FIELD_ID_VERSION: z.string().optional(),
NEXT_PUBLIC_ZENDESK_FIELD_ID_WORKSPACE_ID: z.string().optional(),
NEXT_PUBLIC_ZENDESK_WIDGET_KEY: z.string().optional(),
} satisfies ClientSchema
export const env = createEnv({
server: {
ANALYZE: optionalString,
INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH: optionalString,
NEXT_TELEMETRY_DISABLED: optionalString,
PORT: optionalString,
TEXT_GENERATION_TIMEOUT_MS: optionalString,
ANALYZE: coercedBoolean.default(false),
/**
* Maximum length of segmentation tokens for indexing
*/
INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH: coercedNumber.default(4000),
/**
* Disable Next.js Telemetry (https://nextjs.org/telemetry)
*/
NEXT_TELEMETRY_DISABLED: coercedBoolean.optional(),
PORT: coercedNumber.default(3000),
/**
* The timeout for the text generation in millisecond
*/
TEXT_GENERATION_TIMEOUT_MS: coercedNumber.default(60000),
},
shared: {
NODE_ENV: z.enum(['development', 'test', 'production']).default('development'),

View File

@@ -1614,11 +1614,6 @@
"count": 1
}
},
"app/components/base/param-item/top-k-item.tsx": {
"unicorn/prefer-number-properties": {
"count": 1
}
},
"app/components/base/portal-to-follow-elem/index.tsx": {
"react-refresh/only-export-components": {
"count": 2
@@ -4055,11 +4050,6 @@
"count": 4
}
},
"app/components/workflow/nodes/knowledge-base/components/retrieval-setting/top-k-and-score-threshold.tsx": {
"unicorn/prefer-number-properties": {
"count": 1
}
},
"app/components/workflow/nodes/knowledge-base/components/retrieval-setting/type.ts": {
"ts/no-explicit-any": {
"count": 2

View File

@@ -18,12 +18,12 @@ const withMDX = createMDX({
},
})
const withBundleAnalyzer = withBundleAnalyzerInit({
enabled: env.ANALYZE === 'true',
enabled: env.ANALYZE ?? false,
})
// the default url to prevent parse url error when running jest
const hasSetWebPrefix = env.NEXT_PUBLIC_WEB_PREFIX
const port = env.PORT || '3000'
const port = env.PORT ?? 3000
const locImageURLs = !hasSetWebPrefix ? [new URL(`http://localhost:${port}/**`), new URL(`http://127.0.0.1:${port}/**`)] : []
const remoteImageURLs = ([hasSetWebPrefix ? new URL(`${env.NEXT_PUBLIC_WEB_PREFIX}/**`) : '', ...locImageURLs].filter(item => !!item)) as URL[]

View File

@@ -8,7 +8,7 @@ const NECESSARY_DOMAIN = '*.sentry.io http://localhost:* http://127.0.0.1:* http
const wrapResponseWithXFrameOptions = (response: NextResponse, pathname: string) => {
// prevent clickjacking: https://owasp.org/www-community/attacks/Clickjacking
// Chatbot page should be allowed to be embedded in iframe. It's a feature
if (env.NEXT_PUBLIC_ALLOW_EMBED !== 'true' && !pathname.startsWith('/chat') && !pathname.startsWith('/workflow') && !pathname.startsWith('/completion') && !pathname.startsWith('/webapp-signin'))
if (env.NEXT_PUBLIC_ALLOW_EMBED !== true && !pathname.startsWith('/chat') && !pathname.startsWith('/workflow') && !pathname.startsWith('/completion') && !pathname.startsWith('/webapp-signin'))
response.headers.set('X-Frame-Options', 'DENY')
return response