fix(workflow): allow KnowledgeFS top n up to 100

This commit is contained in:
Stephen Zhou 2026-09-01 20:22:46 +08:00
parent 66a93d5dfb
commit 73e449c3ef
No known key found for this signature in database
8 changed files with 50 additions and 17 deletions

View File

@ -109,15 +109,17 @@ describe('ParamItem', () => {
expect(defaultProps.onChange).toHaveBeenLastCalledWith('test_param', 0.8)
})
it('should reset the textbox and slider when users clear the input', async () => {
it('should allow users to replace the minimum value with a multi-digit value', async () => {
const user = userEvent.setup()
const StatefulParamItem = () => {
const [value, setValue] = useState(defaultProps.value)
const [value, setValue] = useState(1)
return (
<ParamItem
{...defaultProps}
value={value}
min={1}
max={100}
onChange={(key: string, nextValue: number) => {
defaultProps.onChange(key, nextValue)
setValue(nextValue)
@ -131,12 +133,14 @@ describe('ParamItem', () => {
const input = screen.getByRole('textbox')
await user.clear(input)
expect(defaultProps.onChange).toHaveBeenLastCalledWith('test_param', 0)
expect(getSlider()).toHaveAttribute('aria-valuenow', '0')
expect(input).toHaveValue('')
expect(defaultProps.onChange).not.toHaveBeenCalled()
await user.tab()
await user.type(input, '20')
expect(input).toHaveValue('0')
expect(input).toHaveValue('20')
expect(defaultProps.onChange).toHaveBeenLastCalledWith('test_param', 20)
expect(getSlider()).toHaveAttribute('aria-valuenow', '20')
})
it('should clamp out-of-range text edits before updating state', async () => {

View File

@ -75,6 +75,12 @@ describe('TopKItem', () => {
expect(input).toBeInTheDocument()
})
it('should allow a feature-specific maximum', () => {
render(<TopKItem {...defaultProps} max={100} />)
expect(getSlider()).toHaveAttribute('max', '100')
})
it('should render slider with max >= 5 so no scaling is applied', () => {
render(<TopKItem {...defaultProps} />)
const slider = getSlider()

View File

@ -85,7 +85,9 @@ const ParamItem: FC<Props> = ({
max={max}
step={step}
value={value}
onValueChange={(nextValue) => onChange(id, nextValue ?? min)}
onValueChange={(nextValue) => {
if (nextValue !== null) onChange(id, nextValue)
}}
>
<NumberFieldGroup>
<NumberFieldInput aria-label={name} className="w-18" />

View File

@ -11,22 +11,28 @@ type Props = Readonly<{
onChange: (key: string, value: number) => void
enable: boolean
disabled?: boolean
max?: number
}>
const maxTopK = env.NEXT_PUBLIC_TOP_K_MAX_VALUE
const VALUE_LIMIT = {
default: 2,
step: 1,
min: 1,
max: maxTopK,
}
const TopKItem: FC<Props> = ({ className, value, enable, onChange, disabled = false }) => {
const TopKItem: FC<Props> = ({
className,
value,
enable,
onChange,
disabled = false,
max = env.NEXT_PUBLIC_TOP_K_MAX_VALUE,
}) => {
const { t } = useTranslation()
const handleParamChange = (key: string, value: number) => {
let notOutRangeValue = Number.parseInt(value.toFixed(0))
notOutRangeValue = Math.max(VALUE_LIMIT.min, notOutRangeValue)
notOutRangeValue = Math.min(VALUE_LIMIT.max, notOutRangeValue)
notOutRangeValue = Math.min(max, notOutRangeValue)
onChange(key, notOutRangeValue)
}
return (
@ -36,6 +42,7 @@ const TopKItem: FC<Props> = ({ className, value, enable, onChange, disabled = fa
name={t(($) => $['datasetConfig.top_k'], { ns: 'appDebug' })}
tip={t(($) => $['datasetConfig.top_kTip'], { ns: 'appDebug' }) as string}
{...VALUE_LIMIT}
max={max}
value={value}
enable={enable}
disabled={disabled}

View File

@ -3,6 +3,7 @@ import { fireEvent, render, screen } from '@testing-library/react'
import RecallSettings from '../recall-settings'
const mockModelSelector = vi.hoisted(() => vi.fn())
const mockTopKItem = vi.hoisted(() => vi.fn())
vi.mock('@/app/components/header/account-setting/model-provider-page/hooks', () => ({
useModelListAndDefaultModelAndCurrentProviderAndModel: () => ({
@ -45,11 +46,18 @@ vi.mock('@langgenius/dify-ui/select', () => ({
}))
vi.mock('@/app/components/base/param-item/top-k-item', () => ({
default: (props: { onChange: (key: string, value: number) => void; value: number }) => (
<button type="button" onClick={() => props.onChange('top_k', 20)}>
top-{props.value}
</button>
),
default: (props: {
max?: number
onChange: (key: string, value: number) => void
value: number
}) => {
mockTopKItem(props)
return (
<button type="button" onClick={() => props.onChange('top_k', 20)}>
top-{props.value}
</button>
)
},
}))
vi.mock('@/app/components/base/param-item/score-threshold-item', () => ({
@ -86,6 +94,7 @@ describe('RecallSettings', () => {
)
expect(screen.getByText('common.modelProvider.defaultConfig')).toBeInTheDocument()
expect(mockTopKItem).toHaveBeenLastCalledWith(expect.objectContaining({ max: 100 }))
expect(mockModelSelector).toHaveBeenLastCalledWith(
expect.objectContaining({
value: { provider: 'system/provider', model: 'system-rerank' },

View File

@ -20,6 +20,7 @@ import TopKItem from '@/app/components/base/param-item/top-k-item'
import { ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
import { useModelListAndDefaultModelAndCurrentProviderAndModel } from '@/app/components/header/account-setting/model-provider-page/hooks'
import { ModelSelector } from '@/app/components/header/account-setting/model-provider-page/model-selector'
import { KNOWLEDGE_RETRIEVAL_V2_TOP_N_MAX } from '../constants'
const i18nPrefix = 'nodes.knowledgeRetrievalV2'
const DEFAULT_SCORE_THRESHOLD = 0.5
@ -186,6 +187,7 @@ const RecallSettings: FC<Props> = ({
value={topK}
enable
disabled={readonly}
max={KNOWLEDGE_RETRIEVAL_V2_TOP_N_MAX}
onChange={(_, value) => onTopKChange(value)}
/>
<ScoreThresholdItem

View File

@ -52,3 +52,5 @@ export const KNOWLEDGE_RETRIEVAL_V2_NODE_KINDS = [
'image',
'summary',
] as const
export const KNOWLEDGE_RETRIEVAL_V2_TOP_N_MAX = 100

View File

@ -27,6 +27,7 @@ import {
import { useNodesReadOnly } from '../../hooks/use-workflow'
import { VarType } from '../../types'
import { toggleControlSpaceId } from './config-helpers'
import { KNOWLEDGE_RETRIEVAL_V2_TOP_N_MAX } from './constants'
const useConfig = (id: string, payload: KnowledgeRetrievalV2NodeType) => {
const { nodesReadOnly: readOnly } = useNodesReadOnly()
@ -91,7 +92,7 @@ const useConfig = (id: string, payload: KnowledgeRetrievalV2NodeType) => {
const handleTopNChange = useCallback(
(topN: number) => {
if (!Number.isInteger(topN) || topN < 1 || topN > 100) return
if (!Number.isInteger(topN) || topN < 1 || topN > KNOWLEDGE_RETRIEVAL_V2_TOP_N_MAX) return
setInputs(
produce(inputs, (draft) => {
draft.top_n = topN