onSelect(tone.id)}>
{TONE_ICONS[tone.id]}
{t(toneI18nKeyMap[tone.name], { ns: 'common' })}
diff --git a/web/app/components/plugins/plugin-detail-panel/model-selector/__tests__/llm-params-panel.spec.tsx b/web/app/components/plugins/plugin-detail-panel/model-selector/__tests__/llm-params-panel.spec.tsx
index 17fad8d7a7..5525934d26 100644
--- a/web/app/components/plugins/plugin-detail-panel/model-selector/__tests__/llm-params-panel.spec.tsx
+++ b/web/app/components/plugins/plugin-detail-panel/model-selector/__tests__/llm-params-panel.spec.tsx
@@ -75,14 +75,58 @@ vi.mock('@/config', () => ({
// Mock PresetsParameter component
vi.mock('@/app/components/header/account-setting/model-provider-page/model-parameter-modal/presets-parameter', () => ({
- default: ({ onSelect }: { onSelect: (toneId: number) => void }) => (
-
-
-
-
-
-
- ),
+ default: ({ onSelect, supportedParameterNames }: { onSelect: (toneId: number) => void, supportedParameterNames?: string[] }) => {
+ const hasSupportedParameter = !supportedParameterNames || supportedParameterNames.some(name => ['temperature', 'top_p', 'presence_penalty', 'frequency_penalty'].includes(name))
+ if (!hasSupportedParameter)
+ return null
+
+ return (
+
+
+
+
+
+
+ )
+ },
+}))
+
+vi.mock('@/app/components/header/account-setting/model-provider-page/model-parameter-modal/presets-parameter-utils', () => ({
+ getSupportedPresetConfig: (toneId: number, supportedParameterNames?: string[]) => {
+ const toneConfigMap: Record | undefined> = {
+ 1: {
+ temperature: 0.8,
+ top_p: 0.9,
+ presence_penalty: 0.1,
+ frequency_penalty: 0.1,
+ },
+ 2: {
+ temperature: 0.5,
+ top_p: 0.85,
+ presence_penalty: 0.2,
+ frequency_penalty: 0.3,
+ },
+ 3: {
+ temperature: 0.2,
+ top_p: 0.75,
+ presence_penalty: 0.5,
+ frequency_penalty: 0.5,
+ },
+ }
+ const toneConfig = toneConfigMap[toneId]
+ if (!toneConfig)
+ return {}
+
+ if (!supportedParameterNames)
+ return toneConfig
+
+ return Object.entries(toneConfig).reduce>((acc, [key, value]) => {
+ if (supportedParameterNames.includes(key))
+ acc[key] = value
+
+ return acc
+ }, {})
+ },
}))
// Mock ParameterItem component
@@ -202,7 +246,7 @@ describe('LLMParamsPanel', () => {
it('should render PresetsParameter for openai provider', () => {
// Arrange
- setupModelParameterRulesMock({ data: [], isPending: false })
+ setupModelParameterRulesMock({ data: [createParameterRule({ name: 'temperature' })], isPending: false })
const props = createDefaultProps({ provider: 'langgenius/openai/openai' })
// Act
@@ -214,7 +258,7 @@ describe('LLMParamsPanel', () => {
it('should render PresetsParameter for azure_openai provider', () => {
// Arrange
- setupModelParameterRulesMock({ data: [], isPending: false })
+ setupModelParameterRulesMock({ data: [createParameterRule({ name: 'temperature' })], isPending: false })
const props = createDefaultProps({ provider: 'langgenius/azure_openai/azure_openai' })
// Act
@@ -224,6 +268,18 @@ describe('LLMParamsPanel', () => {
expect(screen.getByTestId('presets-parameter')).toBeInTheDocument()
})
+ it('should not render PresetsParameter when no visible parameter supports presets', () => {
+ // Arrange
+ setupModelParameterRulesMock({ data: [createParameterRule({ name: 'max_tokens', type: 'int' })], isPending: false })
+ const props = createDefaultProps({ provider: 'langgenius/openai/openai' })
+
+ // Act
+ render()
+
+ // Assert
+ expect(screen.queryByTestId('presets-parameter')).not.toBeInTheDocument()
+ })
+
it('should not render PresetsParameter for non-preset providers', () => {
// Arrange
setupModelParameterRulesMock({ data: [], isPending: false })
@@ -360,7 +416,15 @@ describe('LLMParamsPanel', () => {
it('should apply Creative preset config', () => {
// Arrange
const onCompletionParamsChange = vi.fn()
- setupModelParameterRulesMock({ data: [], isPending: false })
+ setupModelParameterRulesMock({
+ data: [
+ createParameterRule({ name: 'temperature' }),
+ createParameterRule({ name: 'top_p' }),
+ createParameterRule({ name: 'presence_penalty' }),
+ createParameterRule({ name: 'frequency_penalty' }),
+ ],
+ isPending: false,
+ })
const props = createDefaultProps({
provider: 'langgenius/openai/openai',
onCompletionParamsChange,
@@ -384,7 +448,15 @@ describe('LLMParamsPanel', () => {
it('should apply Balanced preset config', () => {
// Arrange
const onCompletionParamsChange = vi.fn()
- setupModelParameterRulesMock({ data: [], isPending: false })
+ setupModelParameterRulesMock({
+ data: [
+ createParameterRule({ name: 'temperature' }),
+ createParameterRule({ name: 'top_p' }),
+ createParameterRule({ name: 'presence_penalty' }),
+ createParameterRule({ name: 'frequency_penalty' }),
+ ],
+ isPending: false,
+ })
const props = createDefaultProps({
provider: 'langgenius/openai/openai',
onCompletionParamsChange,
@@ -407,7 +479,15 @@ describe('LLMParamsPanel', () => {
it('should apply Precise preset config', () => {
// Arrange
const onCompletionParamsChange = vi.fn()
- setupModelParameterRulesMock({ data: [], isPending: false })
+ setupModelParameterRulesMock({
+ data: [
+ createParameterRule({ name: 'temperature' }),
+ createParameterRule({ name: 'top_p' }),
+ createParameterRule({ name: 'presence_penalty' }),
+ createParameterRule({ name: 'frequency_penalty' }),
+ ],
+ isPending: false,
+ })
const props = createDefaultProps({
provider: 'langgenius/openai/openai',
onCompletionParamsChange,
@@ -430,7 +510,7 @@ describe('LLMParamsPanel', () => {
it('should apply empty config for Custom preset (spreads undefined)', () => {
// Arrange
const onCompletionParamsChange = vi.fn()
- setupModelParameterRulesMock({ data: [], isPending: false })
+ setupModelParameterRulesMock({ data: [createParameterRule({ name: 'temperature' })], isPending: false })
const props = createDefaultProps({
provider: 'langgenius/openai/openai',
onCompletionParamsChange,
@@ -444,6 +524,27 @@ describe('LLMParamsPanel', () => {
// Assert - Custom preset has no config, so only existing params are kept
expect(onCompletionParamsChange).toHaveBeenCalledWith({ existing: 'value' })
})
+
+ it('should apply only preset config keys supported by visible parameters', () => {
+ // Arrange
+ const onCompletionParamsChange = vi.fn()
+ setupModelParameterRulesMock({ data: [createParameterRule({ name: 'temperature' })], isPending: false })
+ const props = createDefaultProps({
+ provider: 'langgenius/openai/openai',
+ onCompletionParamsChange,
+ completionParams: { existing: 'value' },
+ })
+
+ // Act
+ render()
+ fireEvent.click(screen.getByTestId('preset-creative'))
+
+ // Assert
+ expect(onCompletionParamsChange).toHaveBeenCalledWith({
+ existing: 'value',
+ temperature: 0.8,
+ })
+ })
})
describe('handleParamChange', () => {
diff --git a/web/app/components/plugins/plugin-detail-panel/model-selector/llm-params-panel.tsx b/web/app/components/plugins/plugin-detail-panel/model-selector/llm-params-panel.tsx
index d699621c22..49933f6138 100644
--- a/web/app/components/plugins/plugin-detail-panel/model-selector/llm-params-panel.tsx
+++ b/web/app/components/plugins/plugin-detail-panel/model-selector/llm-params-panel.tsx
@@ -10,7 +10,8 @@ import { useTranslation } from 'react-i18next'
import Loading from '@/app/components/base/loading'
import ParameterItem from '@/app/components/header/account-setting/model-provider-page/model-parameter-modal/parameter-item'
import PresetsParameter from '@/app/components/header/account-setting/model-provider-page/model-parameter-modal/presets-parameter'
-import { PROVIDER_WITH_PRESET_TONE, STOP_PARAMETER_RULE, TONE_LIST } from '@/config'
+import { getSupportedPresetConfig } from '@/app/components/header/account-setting/model-provider-page/model-parameter-modal/presets-parameter-utils'
+import { PROVIDER_WITH_PRESET_TONE, STOP_PARAMETER_RULE } from '@/config'
import { useModelParameterRules } from '@/service/use-common'
type Props = {
@@ -34,15 +35,15 @@ const LLMParamsPanel = ({
const parameterRules: ModelParameterRule[] = useMemo(() => {
return parameterRulesData?.data || []
}, [parameterRulesData])
+ const supportedPresetParameterNames = useMemo(() => {
+ return parameterRules.map(parameterRule => parameterRule.name)
+ }, [parameterRules])
const handleSelectPresetParameter = (toneId: number) => {
- const tone = TONE_LIST.find(tone => tone.id === toneId)
- if (tone) {
- onCompletionParamsChange({
- ...completionParams,
- ...tone.config,
- })
- }
+ onCompletionParamsChange({
+ ...completionParams,
+ ...getSupportedPresetConfig(toneId, supportedPresetParameterNames),
+ })
}
const handleParamChange = (key: string, value: ParameterValue) => {
onCompletionParamsChange({
@@ -77,7 +78,10 @@ const LLMParamsPanel = ({
{t('modelProvider.parameters', { ns: 'common' })}
{
PROVIDER_WITH_PRESET_TONE.includes(provider) && (
-
+
)
}