diff --git a/docs/features/model-top-p-settings/plan.md b/docs/features/model-top-p-settings/plan.md new file mode 100644 index 000000000..393230587 --- /dev/null +++ b/docs/features/model-top-p-settings/plan.md @@ -0,0 +1,38 @@ +# Implementation Plan + +## Approach + +Implement `topP` as an optional generation setting, mirroring the existing session generation settings pipeline while avoiding a forced default. + +## Affected Interfaces + +- `src/shared/types/agent-interface.d.ts`: add optional `topP` to `SessionGenerationSettings`. +- `src/shared/contracts/common.ts`: add optional `topP` to route schemas. +- `src/shared/utils/generationSettingsValidation.ts`: validate `topP` as a finite number in `[0.1, 1]`. +- `src/main/presenter/sqlitePresenter/tables/deepchatSessions.ts`: add `top_p` storage and migration. +- `src/main/presenter/agentRuntimePresenter/index.ts`: sanitize, persist, and pass `topP` through runtime model config. +- `src/main/presenter/llmProviderPresenter/aiSdk/runtime.ts`: include `topP` in AI SDK `generateText` and `streamText` calls and request traces when defined. +- `src/renderer/src/stores/ui/draft.ts`: carry draft `topP` overrides for new sessions. +- `src/renderer/src/components/chat/ChatStatusBar.vue`: show and persist the compact `topP` control. +- i18n `chat.json` and `settings.json` files: add `topP` label, hover description, and validation. +- `topP` number inputs use min `0.1`, max `1`, and step `0.1` so values align with common AI SDK/provider constraints. + +## Data Flow + +1. User edits `topP` in ChatStatusBar. +2. Draft sessions store it in Pinia; active sessions call `sessions.updateGenerationSettings`. +3. Main process validates and stores `topP` as part of session generation settings. +4. Agent runtime adds `topP` to runtime `ModelConfig`. +5. AI SDK runtime includes `topP` only when defined. + +## Compatibility + +- Existing databases migrate by adding nullable `top_p`. +- Existing sessions return no `topP` unless previously set. +- Requests without `topP` preserve current behavior. + +## Test Strategy + +- Run formatting and i18n generation required by repository guidelines. +- Run lint to catch type/schema/template issues. +- Prefer focused type/lint validation over provider integration tests because this is a pass-through parameter. diff --git a/docs/features/model-top-p-settings/spec.md b/docs/features/model-top-p-settings/spec.md new file mode 100644 index 000000000..006540853 --- /dev/null +++ b/docs/features/model-top-p-settings/spec.md @@ -0,0 +1,36 @@ +# Model Top P Settings + +## User Need + +Users need to adjust `top_p` for chat models because many upstream model APIs support nucleus sampling and expose it as a generation parameter. + +## Goal + +Add an optional per-session `topP` generation setting for text chat requests and pass it through to AI SDK text generation when the user explicitly sets it. + +## Acceptance Criteria + +- Users can set `topP` from the chat model advanced settings panel for regular text chat models. +- `topP` accepts values greater than or equal to 0.1 and less than or equal to 1. +- The Top P UI uses the plain label "Top P" and moves explanatory copy into a hover help icon. +- Existing conversations and new sessions continue to work when no `topP` is set. +- `topP` persists with DeepChat session generation settings and survives app restart. +- Text `generateText` and streaming requests pass `topP` to AI SDK only when it is defined. +- Existing Voice.ai TTS `topP` configuration remains independent. + +## Constraints + +- Follow current typed route/contracts and presenter boundaries. +- Use `topP` internally and let SDK/provider layers map provider payload details. +- Do not default-send `topP: 1`; omit the parameter when unset to preserve provider defaults. +- Use i18n keys for all user-facing strings. +- SQLite schema migration must be backward compatible. + +## Non-Goals + +- Provider-specific `top_p` compatibility matrices. +- Building a full Provider DB `top_p` capability matrix. + +## Open Questions + +- None. diff --git a/docs/features/model-top-p-settings/tasks.md b/docs/features/model-top-p-settings/tasks.md new file mode 100644 index 000000000..af489579a --- /dev/null +++ b/docs/features/model-top-p-settings/tasks.md @@ -0,0 +1,10 @@ +# Tasks + +- [x] Create SDD artifacts for optional model `topP` setting. +- [x] Add shared types, contracts, and validation support for `topP`. +- [x] Add SQLite session persistence and migration for `topP`. +- [x] Propagate `topP` through runtime model config and AI SDK calls. +- [x] Add renderer draft state and advanced settings UI for `topP`. +- [x] Add i18n strings for `topP` controls and validation. +- [x] Refine Top P UI to use a help tooltip and `[0.1, 1]` number input range. +- [x] Run `pnpm run format`, `pnpm run i18n`, and `pnpm run lint`. diff --git a/docs/issues/chat-top-p-tooltip/plan.md b/docs/issues/chat-top-p-tooltip/plan.md new file mode 100644 index 000000000..bb78faca8 --- /dev/null +++ b/docs/issues/chat-top-p-tooltip/plan.md @@ -0,0 +1,22 @@ +# Plan + +## Approach + +The current nested `Tooltip` is fragile inside the model settings `Popover` and can render beneath or outside the visible stacking context. Replace it with a controlled lightweight hover/focus panel anchored next to the Top P label. This keeps tooltip-style interaction while avoiding portal stacking conflicts. + +## Affected Interfaces + +- `src/renderer/src/components/chat/ChatStatusBar.vue` + +## Data Flow + +No data flow changes. The same `chat.advancedSettings.topPDescription` i18n string is displayed. + +## Compatibility + +No persisted configuration changes. The chat settings Top P clamp behavior remains unchanged. + +## Test Strategy + +- Static verification of template/script changes. +- Run project formatting/lint commands if package tooling is available. diff --git a/docs/issues/chat-top-p-tooltip/spec.md b/docs/issues/chat-top-p-tooltip/spec.md new file mode 100644 index 000000000..27c9e2e3a --- /dev/null +++ b/docs/issues/chat-top-p-tooltip/spec.md @@ -0,0 +1,28 @@ +# Chat Top P Tooltip + +## User Need + +The chat settings panel Top P help icon must show explanatory text reliably. The settings dialog should keep inline description text, while the chat status bar should keep a hover tooltip interaction. + +## Goal + +Fix the Top P help content in `ChatStatusBar.vue` so it is visible above the settings popover and has a readable width. + +## Acceptance Criteria + +- Hovering the Top P help icon in the chat settings panel shows the Top P description. +- The tooltip is not hidden behind the model settings popover. +- The tooltip content has a readable constrained width for the long description. +- The settings dialog Top P description remains inline text. +- The existing Top P range clamp behavior remains aligned between chat and settings pages. + +## Constraints + +- Keep changes focused to the chat settings Top P help behavior. +- Preserve existing i18n keys and shadcn/reka UI styling patterns where practical. +- Do not introduce new dependencies. + +## Non-goals + +- Redesign the full chat settings panel. +- Change Top P semantics or persisted data shape. diff --git a/docs/issues/chat-top-p-tooltip/tasks.md b/docs/issues/chat-top-p-tooltip/tasks.md new file mode 100644 index 000000000..6df0aa9e0 --- /dev/null +++ b/docs/issues/chat-top-p-tooltip/tasks.md @@ -0,0 +1,5 @@ +# Tasks + +- [x] Inspect current Top P tooltip implementation and popover stacking. +- [x] Add a layer-safe tooltip-style hover/focus panel for Top P in chat settings. +- [ ] Verify formatting and report any unavailable validation tooling. diff --git a/src/main/presenter/agentRuntimePresenter/index.ts b/src/main/presenter/agentRuntimePresenter/index.ts index 2a16a546c..756b05eb8 100644 --- a/src/main/presenter/agentRuntimePresenter/index.ts +++ b/src/main/presenter/agentRuntimePresenter/index.ts @@ -154,6 +154,11 @@ type PackageJsonManifest = { scripts?: Record } +function normalizeTopP(value: unknown): number | undefined { + const numeric = parseFiniteNumericValue(value) + return numeric !== undefined && numeric >= 0.1 && numeric <= 1 ? numeric : undefined +} + function readPackageJsonManifest(workdir: string): PackageJsonManifest | null { try { const packageJsonPath = path.join(workdir, 'package.json') @@ -202,6 +207,7 @@ type PersistedSessionGenerationRow = { permission_mode: PermissionMode system_prompt: string | null temperature: number | null + top_p: number | null context_length: number | null max_tokens: number | null timeout_ms: number | null @@ -1237,7 +1243,6 @@ export class AgentRuntimePresenter implements IAgentImplementation { if (!state && !dbSession) { throw new Error(`Session ${sessionId} not found`) } - const providerId = state?.providerId ?? dbSession?.provider_id const modelId = state?.modelId ?? dbSession?.model_id if (!providerId || !modelId) { @@ -1987,6 +1992,7 @@ export class AgentRuntimePresenter implements IAgentImplementation { const modelConfig: ModelConfig = { ...baseModelConfig, temperature: generationSettings.temperature, + topP: generationSettings.topP, contextLength: generationSettings.contextLength, maxTokens: capAgentRequestMaxTokens(generationSettings.maxTokens, contextBudgetLength), timeout: generationSettings.timeout, @@ -3328,6 +3334,9 @@ export class AgentRuntimePresenter implements IAgentImplementation { if (sessionRow.temperature !== null) { patch.temperature = sessionRow.temperature } + if (sessionRow.top_p !== null) { + patch.topP = sessionRow.top_p + } if (sessionRow.context_length !== null) { patch.contextLength = sessionRow.context_length } @@ -3375,6 +3384,9 @@ export class AgentRuntimePresenter implements IAgentImplementation { if (Object.prototype.hasOwnProperty.call(requestedPatch, 'temperature')) { patch.temperature = sanitized.temperature } + if (Object.prototype.hasOwnProperty.call(requestedPatch, 'topP')) { + patch.topP = sanitized.topP + } if (Object.prototype.hasOwnProperty.call(requestedPatch, 'contextLength')) { patch.contextLength = sanitized.contextLength } @@ -3402,6 +3414,9 @@ export class AgentRuntimePresenter implements IAgentImplementation { if (Object.prototype.hasOwnProperty.call(requestedPatch, 'imageGeneration')) { patch.imageGeneration = sanitized.imageGeneration } + if (Object.prototype.hasOwnProperty.call(requestedPatch, 'videoGeneration')) { + patch.videoGeneration = sanitized.videoGeneration + } return patch } @@ -3412,6 +3427,7 @@ export class AgentRuntimePresenter implements IAgentImplementation { return { systemPrompt: settings.systemPrompt, temperature: settings.temperature, + topP: settings.topP, contextLength: settings.contextLength, maxTokens: settings.maxTokens, timeout: settings.timeout, @@ -3420,7 +3436,8 @@ export class AgentRuntimePresenter implements IAgentImplementation { reasoningVisibility: settings.reasoningVisibility, verbosity: settings.verbosity, forceInterleavedThinkingCompat: settings.forceInterleavedThinkingCompat, - imageGeneration: settings.imageGeneration + imageGeneration: settings.imageGeneration, + videoGeneration: settings.videoGeneration } } @@ -3466,6 +3483,7 @@ export class AgentRuntimePresenter implements IAgentImplementation { fixedTemperatureKimi?.temperature ?? parseFiniteNumericValue(modelConfig.temperature) ?? 0.7, + topP: normalizeTopP(modelConfig.topP), contextLength: contextLengthDefault, timeout: timeoutDefault >= MODEL_TIMEOUT_MIN_MS && timeoutDefault <= MODEL_TIMEOUT_MAX_MS @@ -3607,6 +3625,15 @@ export class AgentRuntimePresenter implements IAgentImplementation { } } + if (Object.prototype.hasOwnProperty.call(patch, 'topP')) { + const normalizedTopP = normalizeTopP(patch.topP) + if (normalizedTopP !== undefined) { + next.topP = normalizedTopP + } else { + delete next.topP + } + } + if (Object.prototype.hasOwnProperty.call(patch, 'timeout')) { const error = validateGenerationNumericField('timeout', patch.timeout) const numeric = toValidNonNegativeInteger(parseFiniteNumericValue(patch.timeout)) diff --git a/src/main/presenter/configPresenter/modelConfig.ts b/src/main/presenter/configPresenter/modelConfig.ts index fcd2c709c..119f207f8 100644 --- a/src/main/presenter/configPresenter/modelConfig.ts +++ b/src/main/presenter/configPresenter/modelConfig.ts @@ -184,6 +184,7 @@ export class ModelConfigHelper { contextLength: resolveModelContextLength(model.limit?.context), timeout: DEFAULT_MODEL_TIMEOUT, temperature: 0.6, + topP: undefined, vision: isImageInputSupported(model), speechRecognition: false, functionCall: resolveModelFunctionCall(model.tool_call), @@ -488,6 +489,7 @@ export class ModelConfigHelper { ...DEFAULT_MODEL_CAPABILITY_FALLBACKS, timeout: DEFAULT_MODEL_TIMEOUT, temperature: 0.6, + topP: undefined, type: ModelType.Chat, apiEndpoint: ApiEndpointType.Chat, endpointType: undefined, @@ -512,6 +514,7 @@ export class ModelConfigHelper { contextLength: storedConfig.contextLength ?? finalConfig.contextLength, timeout: storedConfig.timeout ?? finalConfig.timeout, temperature: storedConfig.temperature ?? finalConfig.temperature, + topP: storedConfig.topP ?? finalConfig.topP, vision: storedConfig.vision ?? finalConfig.vision, speechRecognition: storedConfig.speechRecognition ?? finalConfig.speechRecognition, functionCall: storedConfig.functionCall ?? finalConfig.functionCall, diff --git a/src/main/presenter/llmProviderPresenter/aiSdk/runtime.ts b/src/main/presenter/llmProviderPresenter/aiSdk/runtime.ts index bf5cf959b..e54222a6b 100644 --- a/src/main/presenter/llmProviderPresenter/aiSdk/runtime.ts +++ b/src/main/presenter/llmProviderPresenter/aiSdk/runtime.ts @@ -1178,7 +1178,8 @@ export async function runAiSdkGenerateText( maxOutputTokens: maxTokens, ...(shouldSendTemperature && resolvedTemperature !== undefined ? { temperature: resolvedTemperature } - : {}) + : {}), + ...(normalizedModelConfig.topP !== undefined ? { topP: normalizedModelConfig.topP } : {}) } await context.emitRequestTrace?.(normalizedModelConfig, { @@ -1195,6 +1196,7 @@ export async function runAiSdkGenerateText( ...(shouldSendTemperature && resolvedTemperature !== undefined ? { temperature: resolvedTemperature } : {}), + ...(normalizedModelConfig.topP !== undefined ? { topP: normalizedModelConfig.topP } : {}), maxOutputTokens: maxTokens }) @@ -1380,6 +1382,7 @@ export async function* runAiSdkCoreStream( ...(shouldSendTemperature && resolvedTemperature !== undefined ? { temperature: resolvedTemperature } : {}), + ...(normalizedModelConfig.topP !== undefined ? { topP: normalizedModelConfig.topP } : {}), tools: tools.map((tool) => tool.function.name) } @@ -1398,6 +1401,7 @@ export async function* runAiSdkCoreStream( ...(shouldSendTemperature && resolvedTemperature !== undefined ? { temperature: resolvedTemperature } : {}), + ...(normalizedModelConfig.topP !== undefined ? { topP: normalizedModelConfig.topP } : {}), maxOutputTokens: maxTokens }) diff --git a/src/main/presenter/sqlitePresenter/schemaCatalog.ts b/src/main/presenter/sqlitePresenter/schemaCatalog.ts index ce55a8fe9..914f36bd0 100644 --- a/src/main/presenter/sqlitePresenter/schemaCatalog.ts +++ b/src/main/presenter/sqlitePresenter/schemaCatalog.ts @@ -117,6 +117,7 @@ const CATALOG_DEFINITIONS: CatalogDefinition[] = [ repairableColumns: { system_prompt: 'ALTER TABLE deepchat_sessions ADD COLUMN system_prompt TEXT;', temperature: 'ALTER TABLE deepchat_sessions ADD COLUMN temperature REAL;', + top_p: 'ALTER TABLE deepchat_sessions ADD COLUMN top_p REAL;', context_length: 'ALTER TABLE deepchat_sessions ADD COLUMN context_length INTEGER;', max_tokens: 'ALTER TABLE deepchat_sessions ADD COLUMN max_tokens INTEGER;', thinking_budget: 'ALTER TABLE deepchat_sessions ADD COLUMN thinking_budget INTEGER;', @@ -131,7 +132,9 @@ const CATALOG_DEFINITIONS: CatalogDefinition[] = [ 'ALTER TABLE deepchat_sessions ADD COLUMN force_interleaved_thinking_compat INTEGER;', reasoning_visibility: 'ALTER TABLE deepchat_sessions ADD COLUMN reasoning_visibility TEXT;', image_generation_options_json: - 'ALTER TABLE deepchat_sessions ADD COLUMN image_generation_options_json TEXT;' + 'ALTER TABLE deepchat_sessions ADD COLUMN image_generation_options_json TEXT;', + video_generation_options_json: + 'ALTER TABLE deepchat_sessions ADD COLUMN video_generation_options_json TEXT;' }, typeCheckedColumns: [ 'summary_cursor_order_seq', diff --git a/src/main/presenter/sqlitePresenter/tables/deepchatSessions.ts b/src/main/presenter/sqlitePresenter/tables/deepchatSessions.ts index 7993f9742..0d0235693 100644 --- a/src/main/presenter/sqlitePresenter/tables/deepchatSessions.ts +++ b/src/main/presenter/sqlitePresenter/tables/deepchatSessions.ts @@ -21,6 +21,7 @@ type DeepChatSessionGenerationSettings = Pick< SessionGenerationSettings, | 'systemPrompt' | 'temperature' + | 'topP' | 'contextLength' | 'maxTokens' | 'timeout' @@ -40,6 +41,7 @@ export interface DeepChatSessionRow { permission_mode: 'default' | 'full_access' system_prompt: string | null temperature: number | null + top_p: number | null context_length: number | null max_tokens: number | null timeout_ms: number | null @@ -119,6 +121,10 @@ export class DeepChatSessionsTable extends BaseTable { columns.push('video_generation_options_json TEXT') } + if (version >= 29) { + columns.push('top_p REAL') + } + if (version >= 14) { columns.push( 'summary_text TEXT', @@ -158,6 +164,9 @@ export class DeepChatSessionsTable extends BaseTable { if (!this.hasColumn('context_length')) { statements.push('ALTER TABLE deepchat_sessions ADD COLUMN context_length INTEGER;') } + if (!this.hasColumn('top_p')) { + statements.push('ALTER TABLE deepchat_sessions ADD COLUMN top_p REAL;') + } if (!this.hasColumn('max_tokens')) { statements.push('ALTER TABLE deepchat_sessions ADD COLUMN max_tokens INTEGER;') } @@ -248,11 +257,14 @@ export class DeepChatSessionsTable extends BaseTable { if (version === 28) { return 'ALTER TABLE deepchat_sessions ADD COLUMN video_generation_options_json TEXT;' } + if (version === 29) { + return 'ALTER TABLE deepchat_sessions ADD COLUMN top_p REAL;' + } return null } getLatestVersion(): number { - return 28 + return 29 } private serializeImageGenerationOptions( @@ -311,6 +323,7 @@ export class DeepChatSessionsTable extends BaseTable { permission_mode, system_prompt, temperature, + top_p, context_length, max_tokens, timeout_ms, @@ -325,7 +338,7 @@ export class DeepChatSessionsTable extends BaseTable { summary_cursor_order_seq, summary_updated_at ) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)` + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)` ) .run( id, @@ -334,6 +347,7 @@ export class DeepChatSessionsTable extends BaseTable { permissionMode, generationSettings?.systemPrompt ?? null, generationSettings?.temperature ?? null, + generationSettings?.topP ?? null, generationSettings?.contextLength ?? null, generationSettings?.maxTokens ?? null, generationSettings?.timeout ?? null, @@ -374,6 +388,9 @@ export class DeepChatSessionsTable extends BaseTable { if (row.temperature !== null) { settings.temperature = row.temperature } + if (row.top_p !== null) { + settings.topP = row.top_p + } if (row.context_length !== null) { settings.contextLength = row.context_length } @@ -432,6 +449,10 @@ export class DeepChatSessionsTable extends BaseTable { updates.push('temperature = ?') params.push(settings.temperature ?? null) } + if (Object.prototype.hasOwnProperty.call(settings, 'topP')) { + updates.push('top_p = ?') + params.push(settings.topP ?? null) + } if (Object.prototype.hasOwnProperty.call(settings, 'contextLength')) { updates.push('context_length = ?') params.push(settings.contextLength ?? null) diff --git a/src/renderer/src/components/chat/ChatStatusBar.vue b/src/renderer/src/components/chat/ChatStatusBar.vue index 77817d13a..3323f6b37 100644 --- a/src/renderer/src/components/chat/ChatStatusBar.vue +++ b/src/renderer/src/components/chat/ChatStatusBar.vue @@ -263,489 +263,579 @@
-
- -
- - - -
-

- {{ moonshotKimiTemperatureHint }} -

-

- {{ getNumericInputErrorMessage('temperature') }} -

-
- -
- -
- - - -
-

+

- {{ getNumericInputErrorMessage('contextLength') }} -

-
- -
- -
- + + +
+

- - - - + {{ getNumericInputErrorMessage('temperature') }} +

-

- {{ getNumericInputErrorMessage('maxTokens') }} -

-
-
- -
- - - + + + {{ t('chat.advancedSettings.topPDescription') }} + + +
+
+ + + +
+

- - + {{ getNumericInputErrorMessage('topP') }} +

-

- {{ getNumericInputErrorMessage('timeout') }} -

-
- - - - -
- - - - - - {{ option.label }} - - - -
+ + + +

+ {{ getNumericInputErrorMessage('contextLength') }} +

+ -
- - -
- -
- - - - - - {{ option.label }} - - - -
+ + + +

+ {{ getNumericInputErrorMessage('maxTokens') }} +

+ -
-
+
- - {{ thinkingBudgetHint }} - - + + + +
+

+ {{ getNumericInputErrorMessage('timeout') }} +

-
-
+ +
+ +
-

- {{ getNumericInputErrorMessage('thinkingBudget') }} -

-
+ + +
-
-
-
- -

- {{ - t('chat.advancedSettings.forceInterleavedThinkingCompatDescription') - }} -

+
+
+ +
+ + {{ thinkingBudgetHint }} + + +
- +
+ + + +
+

+ {{ getNumericInputErrorMessage('thinkingBudget') }} +

-
+ +
+
+
+ +

+ {{ + t('chat.advancedSettings.forceInterleavedThinkingCompatDescription') + }} +

+
+ +
+
+
@@ -902,6 +992,12 @@ import { } from '@shadcn/components/ui/dropdown-menu' import { Input } from '@shadcn/components/ui/input' import { Popover, PopoverContent, PopoverTrigger } from '@shadcn/components/ui/popover' +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger +} from '@shadcn/components/ui/tooltip' import { Select, SelectContent, @@ -1016,6 +1112,9 @@ type GroupedModelList = { } const TEMPERATURE_STEP = 0.1 +const TOP_P_STEP = 0.1 +const TOP_P_MIN = 0.1 +const TOP_P_MAX = 1 const CONTEXT_LENGTH_STEP = 1024 const MAX_TOKENS_STEP = 128 const TIMEOUT_STEP = 1000 @@ -1058,6 +1157,7 @@ let modelSettingsTargetConfigToken = 0 const activeNumericInput = ref(null) const numericInputDrafts = ref>({ temperature: '', + topP: '', contextLength: '', maxTokens: '', timeout: '', @@ -1067,6 +1167,7 @@ const numericInputErrors = ref< Record >({ temperature: null, + topP: null, contextLength: null, maxTokens: null, timeout: null, @@ -1413,6 +1514,10 @@ const getCommittedNumericInputValue = (field: GenerationNumericField): string => switch (field) { case 'temperature': return String(localSettings.value.temperature) + case 'topP': { + const value = localSettings.value.topP + return value === undefined ? '' : String(value) + } case 'contextLength': return String(localSettings.value.contextLength) case 'maxTokens': @@ -1449,6 +1554,7 @@ const resetNumericInputFieldState = (field: GenerationNumericField): void => { const resetNumericInputState = (): void => { activeNumericInput.value = null resetNumericInputFieldState('temperature') + resetNumericInputFieldState('topP') resetNumericInputFieldState('contextLength') resetNumericInputFieldState('maxTokens') resetNumericInputFieldState('timeout') @@ -1509,6 +1615,8 @@ const getNumericInputErrorMessage = (field: GenerationNumericField): string => { return t('settings.model.modelConfig.validation.timeoutMin') case 'timeout_too_large': return t('settings.model.modelConfig.validation.timeoutMax') + case 'top_p_out_of_range': + return t('chat.advancedSettings.validation.topPRange') } } @@ -1716,6 +1824,14 @@ const invalidateGenerationPersistResponses = () => { } const temperatureInputValue = computed(() => getNumericInputValue('temperature')) +const topPInputValue = computed(() => getNumericInputValue('topP')) +const topPCommittedValue = computed(() => localSettings.value?.topP ?? TOP_P_MAX) +const topPDecreaseDisabled = computed( + () => localSettings.value?.topP === undefined || topPCommittedValue.value <= TOP_P_MIN +) +const topPIncreaseDisabled = computed( + () => localSettings.value?.topP !== undefined && topPCommittedValue.value >= TOP_P_MAX +) const contextLengthInputValue = computed(() => getNumericInputValue('contextLength')) const maxTokensInputValue = computed(() => getNumericInputValue('maxTokens')) const timeoutInputValue = computed(() => getNumericInputValue('timeout')) @@ -1747,6 +1863,9 @@ const showTemperatureControl = computed( (capabilitySupportsTemperature.value !== false || isMoonshotKimiTemperatureLocked.value) && Boolean(localSettings.value) ) +const showTopPControl = computed( + () => !showOpenAIMediaGenerationSettings.value && Boolean(localSettings.value) +) const showVerbosity = computed( () => @@ -2035,6 +2154,7 @@ const resolveDefaultGenerationSettings = async ( systemPrompt: agentConfig.systemPrompt ?? '', temperature: fixedTemperatureKimi?.temperature ?? parseFiniteNumericValue(modelConfig.temperature) ?? 0.7, + topP: normalizeTopP(modelConfig.topP), contextLength: contextLengthDefault, timeout: timeoutDefault >= TIMEOUT_MIN && timeoutDefault <= TIMEOUT_MAX @@ -2241,6 +2361,10 @@ const updateLocalGenerationSettings = (patch: Partial if (Object.prototype.hasOwnProperty.call(nextPatch, 'temperature')) { normalizedPatch.temperature = next.temperature } + if (Object.prototype.hasOwnProperty.call(nextPatch, 'topP')) { + normalizedPatch.topP = normalizeTopP(next.topP) + next.topP = normalizedPatch.topP + } if (Object.prototype.hasOwnProperty.call(nextPatch, 'contextLength')) { normalizedPatch.contextLength = next.contextLength } @@ -2587,6 +2711,7 @@ async function changeModelSelection( const previousDraftGenerationSettings = { systemPrompt: draftStore.systemPrompt, temperature: draftStore.temperature, + topP: draftStore.topP, contextLength: draftStore.contextLength, maxTokens: draftStore.maxTokens, timeout: draftStore.timeout, @@ -2600,6 +2725,7 @@ async function changeModelSelection( } as Partial const clearedDraftModelOverrides = { temperature: undefined, + topP: undefined, contextLength: undefined, maxTokens: undefined, timeout: undefined, @@ -2748,6 +2874,59 @@ function stepTemperature(direction: -1 | 1) { resetNumericInputFieldState('temperature') } +const roundTopPStepValue = (value: number): number => Number(value.toFixed(10)) + +function normalizeTopP(value: unknown): number | undefined { + const numeric = parseFiniteNumericValue(value) + return numeric !== undefined && numeric >= 0.1 && numeric <= 1 ? numeric : undefined +} + +function stepTopP(direction: -1 | 1) { + if (!localSettings.value) { + return + } + if (hasNumericInputError('topP')) { + return + } + if (direction === -1 && localSettings.value.topP === undefined) { + return + } + const current = localSettings.value.topP ?? TOP_P_MAX + const next = Math.min(TOP_P_MAX, Math.max(TOP_P_MIN, current + direction * TOP_P_STEP)) + updateLocalGenerationSettings({ topP: roundTopPStepValue(next) }) + resetNumericInputFieldState('topP') +} + +function onTopPInput(value: string | number) { + setNumericInputDraft('topP', value) +} + +function commitTopPInput() { + if (numericInputDrafts.value.topP.trim() === '') { + stopNumericInputEdit('topP') + clearNumericInputError('topP') + updateLocalGenerationSettings({ topP: undefined }) + resetNumericInputFieldState('topP') + return + } + + const draftNum = parseFiniteNumericValue(numericInputDrafts.value.topP) + if (draftNum !== undefined) { + if (draftNum < TOP_P_MIN) { + numericInputDrafts.value.topP = String(TOP_P_MIN) + } else if (draftNum > TOP_P_MAX) { + numericInputDrafts.value.topP = String(TOP_P_MAX) + } + } + + const next = commitNumericField('topP', numericInputDrafts.value.topP) + if (next === undefined) { + return + } + updateLocalGenerationSettings({ topP: next }) + resetNumericInputFieldState('topP') +} + function onTemperatureInput(value: string | number) { if (isMoonshotKimiTemperatureLocked.value) { return diff --git a/src/renderer/src/components/settings/ModelConfigDialog.vue b/src/renderer/src/components/settings/ModelConfigDialog.vue index b5671b0b2..ab5e4953a 100644 --- a/src/renderer/src/components/settings/ModelConfigDialog.vue +++ b/src/renderer/src/components/settings/ModelConfigDialog.vue @@ -158,6 +158,24 @@

+
+ + +

+ {{ t('settings.model.modelConfig.topP.description') }} +

+

+ {{ errors.topP }} +

+
+
import { ref, computed, watch, onMounted } from 'vue' +import { Icon } from '@iconify/vue' import { storeToRefs } from 'pinia' import { useI18n } from 'vue-i18n' import { @@ -593,6 +612,12 @@ import { Button } from '@shadcn/components/ui/button' import { Input } from '@shadcn/components/ui/input' import { Label } from '@shadcn/components/ui/label' import { Switch } from '@shadcn/components/ui/switch' +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger +} from '@shadcn/components/ui/tooltip' import { Select, SelectContent, @@ -683,6 +708,7 @@ const createDefaultConfig = (): ModelConfig => ({ contextLength: DEFAULT_MODEL_CONTEXT_LENGTH, timeout: DEFAULT_MODEL_TIMEOUT, temperature: 0.7, + topP: undefined, vision: DEFAULT_MODEL_VISION, speechRecognition: DEFAULT_MODEL_SPEECH_RECOGNITION, functionCall: DEFAULT_MODEL_FUNCTION_CALL, @@ -700,6 +726,7 @@ const DEFAULT_VERBOSITY_OPTIONS: Array<'low' | 'medium' | 'high'> = ['low', 'med // 配置数据 const config = ref(createDefaultConfig()) +const topPDraft = ref('') const modelNameField = ref(props.modelName ?? '') const modelIdField = ref(props.modelId ?? '') const originalModelId = ref(props.modelId ?? '') @@ -749,6 +776,33 @@ const showOpenAIMediaGenerationRouteControls = computed( ) const showTtsSettings = computed(() => config.value.type === ModelType.TTS) +const syncTopPDraftFromConfig = () => { + topPDraft.value = typeof config.value.topP === 'number' ? String(config.value.topP) : '' +} + +const parseTopPDraft = (): number | undefined => { + const raw = topPDraft.value.trim() + if (!raw) { + return undefined + } + + return Number(raw) +} + +const clampTopPDraft = () => { + const raw = topPDraft.value.trim() + if (!raw) return + + const num = Number(raw) + if (!Number.isFinite(num)) return + + if (num < 0.1) { + topPDraft.value = '0.1' + } else if (num > 1) { + topPDraft.value = '1' + } +} + // 重置确认对话框 const showResetConfirm = ref(false) @@ -1128,6 +1182,7 @@ const loadConfig = async () => { if (isCreateMode.value) { config.value = createDefaultConfig() + syncTopPDraftFromConfig() syncNewApiDerivedFields() await fetchCapabilities() return @@ -1137,7 +1192,8 @@ const loadConfig = async () => { try { const modelConfig = await modelConfigStore.getModelConfig(props.modelId, props.providerId) - config.value = { ...modelConfig } + config.value = { ...createDefaultConfig(), ...modelConfig } + syncTopPDraftFromConfig() if (showEndpointTypeSelector.value && !isNewApiEndpointType(config.value.endpointType)) { config.value.endpointType = @@ -1160,6 +1216,7 @@ const loadConfig = async () => { } catch (error) { console.error('Failed to load model config:', error) config.value = createDefaultConfig() + syncTopPDraftFromConfig() } await fetchCapabilities() @@ -1275,6 +1332,18 @@ const validateForm = () => { } } + if (!showOpenAIMediaGenerationSettings.value) { + const parsedTopP = parseTopPDraft() + config.value.topP = parsedTopP + if (parsedTopP !== undefined) { + if (!Number.isFinite(parsedTopP)) { + errors.value.topP = t('chat.advancedSettings.validation.finiteNumber') + } else if (parsedTopP < 0.1 || parsedTopP > 1) { + errors.value.topP = t('settings.model.modelConfig.validation.topPRange') + } + } + } + if (config.value.timeout !== undefined && config.value.timeout !== null) { const timeout = Number(config.value.timeout) if (!Number.isFinite(timeout) || timeout < MODEL_TIMEOUT_MIN_MS) { @@ -1308,9 +1377,17 @@ const handleSave = async () => { const timeout = Number(config.value.timeout) const normalizedTimeout = Number.isFinite(timeout) && timeout > 0 ? Math.round(timeout) : undefined + const parsedTopP = parseTopPDraft() const configToSave: ModelConfig = { ...config.value, ...(normalizedTimeout !== undefined ? { timeout: normalizedTimeout } : {}), + topP: + typeof parsedTopP === 'number' && + Number.isFinite(parsedTopP) && + parsedTopP >= 0.1 && + parsedTopP <= 1 + ? parsedTopP + : undefined, imageGeneration: showOpenAIImageGenerationSettings.value ? normalizeImageGenerationOptions(config.value.imageGeneration) : undefined, @@ -1384,6 +1461,7 @@ const confirmReset = async () => { try { if (isCreateMode.value) { config.value = createDefaultConfig() + syncTopPDraftFromConfig() modelNameField.value = '' modelIdField.value = '' showResetConfirm.value = false diff --git a/src/renderer/src/i18n/da-DK/chat.json b/src/renderer/src/i18n/da-DK/chat.json index 9afd6c544..ffe03c76a 100644 --- a/src/renderer/src/i18n/da-DK/chat.json +++ b/src/renderer/src/i18n/da-DK/chat.json @@ -166,6 +166,8 @@ "systemPromptPlaceholder": "Vælg en forudindstilling", "temperature": "Temperatur", "temperatureFixedMoonshotKimi": "Moonshot Kimi K2.5/K2.6 låser temperaturen til {enabled}, når tænkning er aktiveret, og til {disabled}, når den er deaktiveret.", + "topP": "Top P", + "topPDescription": "Nucleus-sampling; lad feltet stå tomt for at bruge udbyderens standard", "contextLength": "Kontekstlængde", "maxTokens": "Maks. tokens", "thinkingBudget": "Tænkebudget", @@ -182,7 +184,8 @@ "finiteNumber": "Skal være et endeligt tal", "nonNegativeInteger": "Skal være et ikke-negativt heltal", "contextLengthAtLeastMaxTokens": "Skal være større end eller lig med maksimumtokens", - "maxTokensWithinContextLength": "Skal være mindre end eller lig med kontekstlængden" + "maxTokensWithinContextLength": "Skal være mindre end eller lig med kontekstlængden", + "topPRange": "Skal være større end 0 og mindre end eller lig med 1" } }, "workspace": { diff --git a/src/renderer/src/i18n/da-DK/settings.json b/src/renderer/src/i18n/da-DK/settings.json index 5ba20e796..65931ae39 100644 --- a/src/renderer/src/i18n/da-DK/settings.json +++ b/src/renderer/src/i18n/da-DK/settings.json @@ -557,6 +557,10 @@ "fixedMoonshotKimi": "Moonshot Kimi K2.5/K2.6 låser temperaturen til {enabled}, når tænkning er aktiveret, og til {disabled}, når den er deaktiveret.", "label": "Temperatur" }, + "topP": { + "label": "Top P", + "description": "Styrer nucleus-sampling. Lad feltet stå tomt for at bruge model- eller udbyderstandarden." + }, "title": "Brugerdefinerede modelparametre", "type": { "description": "Vælg modeltype", @@ -580,7 +584,8 @@ "temperatureMin": "Temperaturen skal være større end eller lig 0", "temperatureRequired": "Temperaturen må ikke være tom", "timeoutMin": "Tidsgrænsen for anmodning skal være mindst 1000ms", - "timeoutMax": "Tidsgrænsen for anmodning må ikke overstige 3600000ms" + "timeoutMax": "Tidsgrænsen for anmodning må ikke overstige 3600000ms", + "topPRange": "Top P skal være større end 0 og mindre end eller lig med 1" }, "vision": { "description": "Understøtter modellen visuelle funktioner?", diff --git a/src/renderer/src/i18n/de-DE/chat.json b/src/renderer/src/i18n/de-DE/chat.json index 3f16bc454..f63f5486b 100644 --- a/src/renderer/src/i18n/de-DE/chat.json +++ b/src/renderer/src/i18n/de-DE/chat.json @@ -177,6 +177,8 @@ "systemPromptPlaceholder": "Voreinstellung auswählen", "temperature": "Temperatur", "temperatureFixedMoonshotKimi": "Moonshot Kimi K2.5/K2.6 ist bei aktiviertem Denken fest auf {enabled} und bei deaktiviertem Denken fest auf {disabled} gesetzt.", + "topP": "Top P", + "topPDescription": "Nucleus Sampling; leer lassen, um den Anbieterstandard zu verwenden", "contextLength": "Kontextlänge", "maxTokens": "Maximale Ausgabe", "thinkingBudget": "Denkbudget", @@ -193,7 +195,8 @@ "finiteNumber": "Muss eine endliche Zahl sein", "nonNegativeInteger": "Muss eine nicht negative ganze Zahl sein", "contextLengthAtLeastMaxTokens": "Muss größer oder gleich der maximalen Ausgabe sein", - "maxTokensWithinContextLength": "Muss kleiner oder gleich der Kontextlänge sein" + "maxTokensWithinContextLength": "Muss kleiner oder gleich der Kontextlänge sein", + "topPRange": "Muss größer als 0 und kleiner oder gleich 1 sein" } }, "modelPicker": { diff --git a/src/renderer/src/i18n/de-DE/settings.json b/src/renderer/src/i18n/de-DE/settings.json index f5254e8d9..1842ed21c 100644 --- a/src/renderer/src/i18n/de-DE/settings.json +++ b/src/renderer/src/i18n/de-DE/settings.json @@ -623,6 +623,10 @@ "description": "Steuert die Zufälligkeit der Ausgabe. Die meisten Modelle nutzen 0-1, manche unterstützen 0-2; je höher, desto zufälliger.", "fixedMoonshotKimi": "Moonshot Kimi K2.5/K2.6 ist bei aktiviertem Denken fest auf {enabled} und bei deaktiviertem Denken fest auf {disabled} gesetzt." }, + "topP": { + "label": "Top P", + "description": "Steuert Nucleus Sampling. Leer lassen, um den Modell- oder Anbieterstandard zu verwenden." + }, "vision": { "label": "Vision-Fähigkeit", "description": "Ob das Modell Vision-Funktionen unterstützt" @@ -723,7 +727,8 @@ "temperatureMin": "Temperatur muss größer oder gleich 0 sein", "temperatureMax": "Temperatur muss kleiner oder gleich 2 sein", "timeoutMin": "Anfrage-Timeout darf nicht kleiner als 1000 Millisekunden sein", - "timeoutMax": "Anfrage-Timeout darf 3600000 Millisekunden nicht überschreiten" + "timeoutMax": "Anfrage-Timeout darf 3600000 Millisekunden nicht überschreiten", + "topPRange": "Top P muss größer als 0 und kleiner oder gleich 1 sein" }, "endpointType": { "label": "Protokolltyp", diff --git a/src/renderer/src/i18n/en-US/chat.json b/src/renderer/src/i18n/en-US/chat.json index a1724717f..e6d92b4d7 100644 --- a/src/renderer/src/i18n/en-US/chat.json +++ b/src/renderer/src/i18n/en-US/chat.json @@ -177,6 +177,8 @@ "systemPromptPlaceholder": "Select a preset", "temperature": "Temperature", "temperatureFixedMoonshotKimi": "Moonshot Kimi K2.5/K2.6 fixes temperature to {enabled} when thinking is enabled and {disabled} when it is disabled.", + "topP": "Top P", + "topPDescription": "Nucleus sampling; leave blank to use provider default", "contextLength": "Context Length", "maxTokens": "Max Tokens", "thinkingBudget": "Thinking Budget", @@ -193,7 +195,8 @@ "finiteNumber": "Must be a finite number", "nonNegativeInteger": "Must be a non-negative integer", "contextLengthAtLeastMaxTokens": "Must be greater than or equal to Max Tokens", - "maxTokensWithinContextLength": "Must be less than or equal to Context Length" + "maxTokensWithinContextLength": "Must be less than or equal to Context Length", + "topPRange": "Must be greater than 0 and less than or equal to 1" } }, "modelPicker": { diff --git a/src/renderer/src/i18n/en-US/settings.json b/src/renderer/src/i18n/en-US/settings.json index e2bf89246..2749ef0e1 100644 --- a/src/renderer/src/i18n/en-US/settings.json +++ b/src/renderer/src/i18n/en-US/settings.json @@ -687,6 +687,10 @@ "fixedMoonshotKimi": "Moonshot Kimi K2.5/K2.6 fixes temperature to {enabled} when thinking is enabled and {disabled} when it is disabled.", "label": "Temperature" }, + "topP": { + "label": "Top P", + "description": "Controls nucleus sampling. Leave blank to use the model or provider default." + }, "title": "Custom model parameters", "type": { "description": "Select the type of model", @@ -710,7 +714,8 @@ "temperatureMin": "The temperature must be greater than or equal to 0", "temperatureRequired": "The temperature cannot be empty", "timeoutMin": "Request timeout must be at least 1000ms", - "timeoutMax": "Request timeout cannot exceed 3600000ms" + "timeoutMax": "Request timeout cannot exceed 3600000ms", + "topPRange": "Top P must be greater than 0 and less than or equal to 1" }, "vision": { "description": "Does the model support visual ability?", diff --git a/src/renderer/src/i18n/es-ES/chat.json b/src/renderer/src/i18n/es-ES/chat.json index 449d42bd8..c937b77b9 100644 --- a/src/renderer/src/i18n/es-ES/chat.json +++ b/src/renderer/src/i18n/es-ES/chat.json @@ -177,6 +177,8 @@ "systemPromptPlaceholder": "Seleccionar preajuste", "temperature": "Temperatura", "temperatureFixedMoonshotKimi": "Moonshot Kimi K2.5/K2.6 fija la temperatura en {enabled} cuando el razonamiento está activado y en {disabled} cuando está desactivado.", + "topP": "Top P", + "topPDescription": "Muestreo núcleo; déjalo vacío para usar el valor predeterminado del proveedor", "contextLength": "Longitud del contexto", "maxTokens": "Tokens máximos", "thinkingBudget": "Presupuesto de razonamiento", @@ -193,7 +195,8 @@ "finiteNumber": "Debe ser un número finito", "nonNegativeInteger": "Debe ser un número entero no negativo", "contextLengthAtLeastMaxTokens": "Debe ser mayor o igual que Tokens máximos", - "maxTokensWithinContextLength": "Debe ser menor o igual que la longitud del contexto" + "maxTokensWithinContextLength": "Debe ser menor o igual que la longitud del contexto", + "topPRange": "Debe ser mayor que 0 y menor o igual que 1" } }, "modelPicker": { diff --git a/src/renderer/src/i18n/es-ES/settings.json b/src/renderer/src/i18n/es-ES/settings.json index cabf0baa5..a630e301f 100644 --- a/src/renderer/src/i18n/es-ES/settings.json +++ b/src/renderer/src/i18n/es-ES/settings.json @@ -623,6 +623,10 @@ "description": "Controlar la aleatoriedad de la salida. La mayoría de los modelos son 0-1 y algunos admiten entre 0-2. Los valores más altos aumentan la aleatoriedad.", "fixedMoonshotKimi": "Moonshot Kimi K2.5/K2.6 fija la temperatura en {enabled} cuando el pensamiento está habilitado y en {disabled} cuando está deshabilitado." }, + "topP": { + "label": "Top P", + "description": "Controla el muestreo núcleo. Déjalo vacío para usar el valor predeterminado del modelo o proveedor." + }, "vision": { "label": "Habilidad visual", "description": "¿El modelo admite la capacidad visual?" @@ -723,7 +727,8 @@ "temperatureMin": "La temperatura debe ser mayor o igual a 0", "temperatureMax": "La temperatura debe ser menor o igual a 2", "timeoutMin": "El tiempo de espera de la solicitud debe ser de al menos 1000 ms.", - "timeoutMax": "El tiempo de espera de la solicitud no puede exceder los 3600000 ms" + "timeoutMax": "El tiempo de espera de la solicitud no puede exceder los 3600000 ms", + "topPRange": "Top P debe ser mayor que 0 y menor o igual que 1" }, "endpointType": { "label": "Tipo de punto final", diff --git a/src/renderer/src/i18n/fa-IR/chat.json b/src/renderer/src/i18n/fa-IR/chat.json index 0be5a7791..401388eb9 100644 --- a/src/renderer/src/i18n/fa-IR/chat.json +++ b/src/renderer/src/i18n/fa-IR/chat.json @@ -166,6 +166,8 @@ "systemPromptPlaceholder": "یک پیش‌تنظیم را انتخاب کنید", "temperature": "دما", "temperatureFixedMoonshotKimi": "Moonshot Kimi K2.5/K2.6 وقتی تفکر فعال باشد دما را روی {enabled} و وقتی غیرفعال باشد روی {disabled} ثابت نگه می‌دارد.", + "topP": "Top P", + "topPDescription": "Nucleus sampling; leave blank to use provider default", "contextLength": "طول زمینه", "maxTokens": "حداکثر توکن", "thinkingBudget": "بودجه تفکر", @@ -182,7 +184,8 @@ "finiteNumber": "باید یک عدد متناهی باشد", "nonNegativeInteger": "باید یک عدد صحیح نامنفی باشد", "contextLengthAtLeastMaxTokens": "باید بزرگ‌تر یا مساوی حداکثر توکن‌ها باشد", - "maxTokensWithinContextLength": "باید کوچک‌تر یا مساوی طول زمینه باشد" + "maxTokensWithinContextLength": "باید کوچک‌تر یا مساوی طول زمینه باشد", + "topPRange": "Must be greater than 0 and less than or equal to 1" } }, "workspace": { diff --git a/src/renderer/src/i18n/fa-IR/settings.json b/src/renderer/src/i18n/fa-IR/settings.json index 9643caffe..16a2a6bcd 100644 --- a/src/renderer/src/i18n/fa-IR/settings.json +++ b/src/renderer/src/i18n/fa-IR/settings.json @@ -624,6 +624,10 @@ "fixedMoonshotKimi": "Moonshot Kimi K2.5/K2.6 وقتی تفکر فعال باشد دما را روی {enabled} و وقتی غیرفعال باشد روی {disabled} ثابت نگه می‌دارد.", "label": "درجه حرارت" }, + "topP": { + "label": "Top P", + "description": "Controls nucleus sampling. Leave blank to use the model or provider default." + }, "title": "پارامترهای مدل سفارشی", "type": { "description": "نوع مدل را انتخاب کنید", @@ -647,7 +651,8 @@ "temperatureMin": "دما باید بیشتر یا برابر با 0 باشد", "temperatureRequired": "درجه حرارت نمی تواند خالی باشد", "timeoutMin": "تایم‌اوت باید حداقل 1000ms باشد", - "timeoutMax": "تایم‌اوت نمی‌تواند از 3600000ms بیشتر باشد" + "timeoutMax": "تایم‌اوت نمی‌تواند از 3600000ms بیشتر باشد", + "topPRange": "Top P must be greater than 0 and less than or equal to 1" }, "vision": { "description": "آیا مدل از توانایی بصری پشتیبانی می کند؟", diff --git a/src/renderer/src/i18n/fr-FR/chat.json b/src/renderer/src/i18n/fr-FR/chat.json index 6e17a6e87..fe390aa44 100644 --- a/src/renderer/src/i18n/fr-FR/chat.json +++ b/src/renderer/src/i18n/fr-FR/chat.json @@ -166,6 +166,8 @@ "systemPromptPlaceholder": "Sélectionner un préréglage", "temperature": "Température", "temperatureFixedMoonshotKimi": "Moonshot Kimi K2.5/K2.6 fixe la température à {enabled} lorsque la réflexion est activée et à {disabled} lorsqu’elle est désactivée.", + "topP": "Top P", + "topPDescription": "Échantillonnage nucleus ; laissez vide pour utiliser la valeur par défaut du fournisseur", "contextLength": "Longueur du contexte", "maxTokens": "Jetons max", "thinkingBudget": "Budget de réflexion", @@ -182,7 +184,8 @@ "finiteNumber": "Doit être un nombre fini", "nonNegativeInteger": "Doit être un entier positif ou nul", "contextLengthAtLeastMaxTokens": "Doit être supérieur ou égal au nombre maximal de tokens", - "maxTokensWithinContextLength": "Doit être inférieur ou égal à la longueur de contexte" + "maxTokensWithinContextLength": "Doit être inférieur ou égal à la longueur de contexte", + "topPRange": "Doit être supérieur à 0 et inférieur ou égal à 1" } }, "workspace": { diff --git a/src/renderer/src/i18n/fr-FR/settings.json b/src/renderer/src/i18n/fr-FR/settings.json index 455161a5b..ce856188e 100644 --- a/src/renderer/src/i18n/fr-FR/settings.json +++ b/src/renderer/src/i18n/fr-FR/settings.json @@ -624,6 +624,10 @@ "fixedMoonshotKimi": "Moonshot Kimi K2.5/K2.6 fixe la température à {enabled} lorsque la réflexion est activée et à {disabled} lorsqu’elle est désactivée.", "label": "Température" }, + "topP": { + "label": "Top P", + "description": "Contrôle l’échantillonnage nucleus. Laissez vide pour utiliser la valeur par défaut du modèle ou du fournisseur." + }, "title": "Paramètres du modèle personnalisé", "type": { "description": "Sélectionnez le type de modèle", @@ -647,7 +651,8 @@ "temperatureMin": "La température doit être supérieure ou égale à 0", "temperatureRequired": "La température ne peut pas être vide", "timeoutMin": "Le délai d'attente doit être d'au moins 1000ms", - "timeoutMax": "Le délai d'attente ne peut pas dépasser 3600000ms" + "timeoutMax": "Le délai d'attente ne peut pas dépasser 3600000ms", + "topPRange": "Top P doit être supérieur à 0 et inférieur ou égal à 1" }, "vision": { "description": "Le modèle soutient-il la capacité visuelle?", diff --git a/src/renderer/src/i18n/he-IL/chat.json b/src/renderer/src/i18n/he-IL/chat.json index 3ff221677..390d50a3e 100644 --- a/src/renderer/src/i18n/he-IL/chat.json +++ b/src/renderer/src/i18n/he-IL/chat.json @@ -166,6 +166,8 @@ "systemPromptPlaceholder": "בחר תבנית", "temperature": "טמפרטורה", "temperatureFixedMoonshotKimi": "Moonshot Kimi K2.5/K2.6 מקבע את הטמפרטורה ל-{enabled} כשהחשיבה מופעלת ול-{disabled} כשהיא כבויה.", + "topP": "Top P", + "topPDescription": "Nucleus sampling; leave blank to use provider default", "contextLength": "אורך הקשר", "maxTokens": "מקסימום טוקנים", "thinkingBudget": "תקציב חשיבה", @@ -182,7 +184,8 @@ "finiteNumber": "חייב להיות מספר סופי", "nonNegativeInteger": "חייב להיות מספר שלם לא שלילי", "contextLengthAtLeastMaxTokens": "חייב להיות גדול או שווה למספר הטוקנים המרבי", - "maxTokensWithinContextLength": "חייב להיות קטן או שווה לאורך ההקשר" + "maxTokensWithinContextLength": "חייב להיות קטן או שווה לאורך ההקשר", + "topPRange": "Must be greater than 0 and less than or equal to 1" } }, "workspace": { diff --git a/src/renderer/src/i18n/he-IL/settings.json b/src/renderer/src/i18n/he-IL/settings.json index f2fd530dd..1bb7fdb80 100644 --- a/src/renderer/src/i18n/he-IL/settings.json +++ b/src/renderer/src/i18n/he-IL/settings.json @@ -624,6 +624,10 @@ "fixedMoonshotKimi": "Moonshot Kimi K2.5/K2.6 מקבע את הטמפרטורה ל-{enabled} כשהחשיבה מופעלת ול-{disabled} כשהיא כבויה.", "label": "טמפרטורה" }, + "topP": { + "label": "Top P", + "description": "Controls nucleus sampling. Leave blank to use the model or provider default." + }, "title": "פרמטרים מותאמים למודל", "type": { "description": "בחר את סוג המודל", @@ -647,7 +651,8 @@ "temperatureMin": "הטמפרטורה חייבת להיות גדולה או שווה ל-0", "temperatureRequired": "הטמפרטורה אינה יכולה להיות ריקה", "timeoutMin": "הטיימאוט חייב להיות לפחות 1000ms", - "timeoutMax": "הטיימאוט אינו יכול לעלות על 3600000ms" + "timeoutMax": "הטיימאוט אינו יכול לעלות על 3600000ms", + "topPRange": "Top P must be greater than 0 and less than or equal to 1" }, "vision": { "description": "האם המודל תומך ביכולת חזותית?", diff --git a/src/renderer/src/i18n/id-ID/chat.json b/src/renderer/src/i18n/id-ID/chat.json index 2eda9bb3a..52af0998a 100644 --- a/src/renderer/src/i18n/id-ID/chat.json +++ b/src/renderer/src/i18n/id-ID/chat.json @@ -177,6 +177,8 @@ "systemPromptPlaceholder": "Pilih preset", "temperature": "suhu", "temperatureFixedMoonshotKimi": "Moonshot Kimi K2.5/K2.6 ditetapkan ke {enabled} saat pemikiran diaktifkan, dan ditetapkan ke {disabled} saat pemikiran dimatikan.", + "topP": "Top P", + "topPDescription": "Nucleus sampling; leave blank to use provider default", "contextLength": "panjang konteks", "maxTokens": "keluaran maksimal", "thinkingBudget": "Pikirkan tentang anggaran", @@ -193,7 +195,8 @@ "finiteNumber": "Harus berupa angka yang terbatas", "nonNegativeInteger": "Harus berupa bilangan bulat non-negatif", "contextLengthAtLeastMaxTokens": "Harus lebih besar atau sama dengan output maksimum", - "maxTokensWithinContextLength": "Harus kurang dari atau sama dengan panjang konteks" + "maxTokensWithinContextLength": "Harus kurang dari atau sama dengan panjang konteks", + "topPRange": "Must be greater than 0 and less than or equal to 1" } }, "modelPicker": { diff --git a/src/renderer/src/i18n/id-ID/settings.json b/src/renderer/src/i18n/id-ID/settings.json index b40fe2bbe..deef01812 100644 --- a/src/renderer/src/i18n/id-ID/settings.json +++ b/src/renderer/src/i18n/id-ID/settings.json @@ -623,6 +623,10 @@ "description": "Kontrol keacakan output. Kebanyakan model mendukung 0-1, dan beberapa mendukung 0-2. Semakin tinggi nilainya, semakin acak.", "fixedMoonshotKimi": "Moonshot Kimi K2.5/K2.6 ditetapkan ke {enabled} saat pemikiran diaktifkan, dan ditetapkan ke {disabled} saat pemikiran dimatikan." }, + "topP": { + "label": "Top P", + "description": "Controls nucleus sampling. Leave blank to use the model or provider default." + }, "vision": { "label": "kemampuan visual", "description": "Apakah model tersebut mendukung kemampuan visual?" @@ -723,7 +727,8 @@ "temperatureMin": "Suhu harus lebih besar dari atau sama dengan 0", "temperatureMax": "Suhu harus kurang dari atau sama dengan 2", "timeoutMin": "Batas waktu permintaan tidak boleh kurang dari 1000 milidetik", - "timeoutMax": "Batas waktu permintaan tidak boleh melebihi 3600000 milidetik" + "timeoutMax": "Batas waktu permintaan tidak boleh melebihi 3600000 milidetik", + "topPRange": "Top P must be greater than 0 and less than or equal to 1" }, "endpointType": { "label": "jenis protokol", diff --git a/src/renderer/src/i18n/it-IT/chat.json b/src/renderer/src/i18n/it-IT/chat.json index 075ab8e72..1a2ea0fbd 100644 --- a/src/renderer/src/i18n/it-IT/chat.json +++ b/src/renderer/src/i18n/it-IT/chat.json @@ -177,6 +177,8 @@ "systemPromptPlaceholder": "Seleziona preset", "temperature": "Temperatura", "temperatureFixedMoonshotKimi": "Moonshot Kimi K2.5/K2.6 usa {enabled} quando il ragionamento è attivo e {disabled} quando è disattivo.", + "topP": "Top P", + "topPDescription": "Campionamento nucleus; lascia vuoto per usare il valore predefinito del provider", "contextLength": "Lunghezza contesto", "maxTokens": "Output massimo", "thinkingBudget": "Budget ragionamento", @@ -193,7 +195,8 @@ "finiteNumber": "Deve essere un numero finito", "nonNegativeInteger": "Deve essere un intero non negativo", "contextLengthAtLeastMaxTokens": "Deve essere maggiore o uguale all'output massimo", - "maxTokensWithinContextLength": "Deve essere minore o uguale alla lunghezza contesto" + "maxTokensWithinContextLength": "Deve essere minore o uguale alla lunghezza contesto", + "topPRange": "Deve essere maggiore di 0 e minore o uguale a 1" } }, "modelPicker": { diff --git a/src/renderer/src/i18n/it-IT/settings.json b/src/renderer/src/i18n/it-IT/settings.json index 1407f5bc3..48cee6ed6 100644 --- a/src/renderer/src/i18n/it-IT/settings.json +++ b/src/renderer/src/i18n/it-IT/settings.json @@ -623,6 +623,10 @@ "description": "Controlla la casualità dell'output. La maggior parte dei modelli usa 0-1, alcuni supportano 0-2; più alto significa più casuale", "fixedMoonshotKimi": "Moonshot Kimi K2.5/K2.6 usa {enabled} quando il ragionamento è attivo e {disabled} quando è disattivo." }, + "topP": { + "label": "Top P", + "description": "Controlla il campionamento nucleus. Lascia vuoto per usare il valore predefinito del modello o del provider." + }, "vision": { "label": "Capacità visiva", "description": "Indica se il modello supporta capacità visive" @@ -723,7 +727,8 @@ "temperatureMin": "La temperatura deve essere maggiore o uguale a 0", "temperatureMax": "La temperatura deve essere minore o uguale a 2", "timeoutMin": "Il timeout richiesta non può essere inferiore a 1000 millisecondi", - "timeoutMax": "Il timeout richiesta non può superare 3600000 millisecondi" + "timeoutMax": "Il timeout richiesta non può superare 3600000 millisecondi", + "topPRange": "Top P deve essere maggiore di 0 e minore o uguale a 1" }, "endpointType": { "label": "Tipo protocollo", diff --git a/src/renderer/src/i18n/ja-JP/chat.json b/src/renderer/src/i18n/ja-JP/chat.json index 2dd76bdcd..eeeeb8150 100644 --- a/src/renderer/src/i18n/ja-JP/chat.json +++ b/src/renderer/src/i18n/ja-JP/chat.json @@ -166,6 +166,8 @@ "systemPromptPlaceholder": "プリセットを選択", "temperature": "温度", "temperatureFixedMoonshotKimi": "Moonshot Kimi K2.5/K2.6 は、思考を有効にすると温度が {enabled} に固定され、無効にすると {disabled} に固定されます。", + "topP": "Top P", + "topPDescription": "核サンプリング。空欄でプロバイダーの既定値を使用", "contextLength": "コンテキスト長", "maxTokens": "最大トークン", "thinkingBudget": "思考予算", @@ -182,7 +184,8 @@ "finiteNumber": "有限の数値である必要があります", "nonNegativeInteger": "0以上の整数である必要があります", "contextLengthAtLeastMaxTokens": "最大トークン数以上である必要があります", - "maxTokensWithinContextLength": "コンテキスト長以下である必要があります" + "maxTokensWithinContextLength": "コンテキスト長以下である必要があります", + "topPRange": "0 より大きく 1 以下である必要があります" } }, "workspace": { diff --git a/src/renderer/src/i18n/ja-JP/settings.json b/src/renderer/src/i18n/ja-JP/settings.json index 342320882..1bab9cf3c 100644 --- a/src/renderer/src/i18n/ja-JP/settings.json +++ b/src/renderer/src/i18n/ja-JP/settings.json @@ -624,6 +624,10 @@ "fixedMoonshotKimi": "Moonshot Kimi K2.5/K2.6 は、思考を有効にすると温度が {enabled} に固定され、無効にすると {disabled} に固定されます。", "label": "温度" }, + "topP": { + "label": "Top P", + "description": "核サンプリングを制御します。空欄でモデルまたはプロバイダーの既定値を使用します。" + }, "title": "カスタムモデルパラメーター", "type": { "description": "モデルのタイプを選択します", @@ -647,7 +651,8 @@ "temperatureMin": "温度は0以上でなければなりません", "temperatureRequired": "温度を空にすることはできません", "timeoutMin": "タイムアウトは最低1000msでなければなりません", - "timeoutMax": "タイムアウトは3600000msを超えることはできません" + "timeoutMax": "タイムアウトは3600000msを超えることはできません", + "topPRange": "Top P は 0 より大きく 1 以下である必要があります" }, "vision": { "description": "モデルは視覚能力をサポートしていますか?", diff --git a/src/renderer/src/i18n/ko-KR/chat.json b/src/renderer/src/i18n/ko-KR/chat.json index 65249f0f2..0339ce4d1 100644 --- a/src/renderer/src/i18n/ko-KR/chat.json +++ b/src/renderer/src/i18n/ko-KR/chat.json @@ -166,6 +166,8 @@ "systemPromptPlaceholder": "프리셋 선택", "temperature": "온도", "temperatureFixedMoonshotKimi": "Moonshot Kimi K2.5/K2.6은 생각이 활성화되면 온도를 {enabled}로, 비활성화되면 {disabled}로 고정합니다.", + "topP": "Top P", + "topPDescription": "핵 샘플링입니다. 비워 두면 제공업체 기본값을 사용합니다", "contextLength": "컨텍스트 길이", "maxTokens": "최대 토큰", "thinkingBudget": "사고 예산", @@ -182,7 +184,8 @@ "finiteNumber": "유한한 숫자여야 합니다", "nonNegativeInteger": "0 이상의 정수여야 합니다", "contextLengthAtLeastMaxTokens": "최대 출력 이상이어야 합니다", - "maxTokensWithinContextLength": "컨텍스트 길이 이하여야 합니다" + "maxTokensWithinContextLength": "컨텍스트 길이 이하여야 합니다", + "topPRange": "0보다 크고 1 이하여야 합니다" } }, "workspace": { diff --git a/src/renderer/src/i18n/ko-KR/settings.json b/src/renderer/src/i18n/ko-KR/settings.json index 43dca7d00..819ad7536 100644 --- a/src/renderer/src/i18n/ko-KR/settings.json +++ b/src/renderer/src/i18n/ko-KR/settings.json @@ -624,6 +624,10 @@ "fixedMoonshotKimi": "Moonshot Kimi K2.5/K2.6은 생각이 활성화되면 온도를 {enabled}로, 비활성화되면 {disabled}로 고정합니다.", "label": "온도" }, + "topP": { + "label": "Top P", + "description": "핵 샘플링 범위를 제어합니다. 비워 두면 모델 또는 제공업체 기본값을 사용합니다." + }, "title": "사용자 정의 모델 매개 변수", "type": { "description": "모델 유형을 선택하십시오", @@ -647,7 +651,8 @@ "temperatureMin": "온도는 0보다 크거나 같아야합니다.", "temperatureRequired": "온도는 비어있을 수 없습니다", "timeoutMin": "요청 시간 초과는 최소 1000ms여야 합니다", - "timeoutMax": "요청 시간 초과는 3600000ms를 초과할 수 없습니다" + "timeoutMax": "요청 시간 초과는 3600000ms를 초과할 수 없습니다", + "topPRange": "Top P는 0보다 크고 1 이하여야 합니다" }, "vision": { "description": "모델이 시각적 능력을 지원합니까?", diff --git a/src/renderer/src/i18n/ms-MY/chat.json b/src/renderer/src/i18n/ms-MY/chat.json index d75044087..7ae4d8b87 100644 --- a/src/renderer/src/i18n/ms-MY/chat.json +++ b/src/renderer/src/i18n/ms-MY/chat.json @@ -177,6 +177,8 @@ "systemPromptPlaceholder": "Pilih pratetap", "temperature": "suhu", "temperatureFixedMoonshotKimi": "Moonshot Kimi K2.5/K2.6 ditetapkan pada {enabled} apabila pemikiran dihidupkan dan {disabled} apabila pemikiran dimatikan.", + "topP": "Top P", + "topPDescription": "Nucleus sampling; leave blank to use provider default", "contextLength": "panjang konteks", "maxTokens": "keluaran maksimum", "thinkingBudget": "Fikirkan tentang bajet", @@ -193,7 +195,8 @@ "finiteNumber": "Mesti nombor terhingga", "nonNegativeInteger": "Mestilah integer bukan negatif", "contextLengthAtLeastMaxTokens": "Mesti lebih besar daripada atau sama dengan keluaran maksimum", - "maxTokensWithinContextLength": "Mesti kurang daripada atau sama dengan panjang konteks" + "maxTokensWithinContextLength": "Mesti kurang daripada atau sama dengan panjang konteks", + "topPRange": "Must be greater than 0 and less than or equal to 1" } }, "modelPicker": { diff --git a/src/renderer/src/i18n/ms-MY/settings.json b/src/renderer/src/i18n/ms-MY/settings.json index 65dfc0de4..dbba327a5 100644 --- a/src/renderer/src/i18n/ms-MY/settings.json +++ b/src/renderer/src/i18n/ms-MY/settings.json @@ -623,6 +623,10 @@ "description": "Kawal rawak keluaran. Kebanyakan model menyokong 0-1, dan beberapa menyokong 0-2. Semakin tinggi nilai, semakin rawak.", "fixedMoonshotKimi": "Moonshot Kimi K2.5/K2.6 ditetapkan pada {enabled} apabila pemikiran dihidupkan dan {disabled} apabila pemikiran dimatikan." }, + "topP": { + "label": "Top P", + "description": "Controls nucleus sampling. Leave blank to use the model or provider default." + }, "vision": { "label": "keupayaan visual", "description": "Adakah model menyokong keupayaan visual?" @@ -723,7 +727,8 @@ "temperatureMin": "Suhu mestilah lebih besar daripada atau sama dengan 0", "temperatureMax": "Suhu mestilah kurang daripada atau sama dengan 2", "timeoutMin": "Tamat masa permintaan tidak boleh kurang daripada 1000 milisaat", - "timeoutMax": "Tamat masa permintaan tidak boleh melebihi 3600000 milisaat" + "timeoutMax": "Tamat masa permintaan tidak boleh melebihi 3600000 milisaat", + "topPRange": "Top P must be greater than 0 and less than or equal to 1" }, "endpointType": { "label": "jenis protokol", diff --git a/src/renderer/src/i18n/pl-PL/chat.json b/src/renderer/src/i18n/pl-PL/chat.json index 0f5f52ae6..3b8f461f1 100644 --- a/src/renderer/src/i18n/pl-PL/chat.json +++ b/src/renderer/src/i18n/pl-PL/chat.json @@ -177,6 +177,8 @@ "systemPromptPlaceholder": "Wybierz ustawienie wstępne", "temperature": "Temperatura", "temperatureFixedMoonshotKimi": "Moonshot Kimi K2.5/K2.6 ustala temperaturę na {enabled}, gdy myślenie jest włączone, i {disabled}, gdy jest wyłączone.", + "topP": "Top P", + "topPDescription": "Nucleus sampling; leave blank to use provider default", "contextLength": "Długość kontekstu", "maxTokens": "Maks. Tokens", "thinkingBudget": "Myślący budżet", @@ -193,7 +195,8 @@ "finiteNumber": "Musi to być liczba skończona", "nonNegativeInteger": "Musi być nieujemną liczbą całkowitą", "contextLengthAtLeastMaxTokens": "Musi być większy lub równy Max Tokens", - "maxTokensWithinContextLength": "Musi być mniejsza lub równa Długość kontekstu" + "maxTokensWithinContextLength": "Musi być mniejsza lub równa Długość kontekstu", + "topPRange": "Must be greater than 0 and less than or equal to 1" } }, "modelPicker": { diff --git a/src/renderer/src/i18n/pl-PL/settings.json b/src/renderer/src/i18n/pl-PL/settings.json index 4d0721b8d..86a69046e 100644 --- a/src/renderer/src/i18n/pl-PL/settings.json +++ b/src/renderer/src/i18n/pl-PL/settings.json @@ -687,6 +687,10 @@ "fixedMoonshotKimi": "Moonshot Kimi K2.5/K2.6 ustala temperaturę na {enabled}, gdy myślenie jest włączone, i {disabled}, gdy jest wyłączone.", "label": "Temperatura" }, + "topP": { + "label": "Top P", + "description": "Controls nucleus sampling. Leave blank to use the model or provider default." + }, "title": "Niestandardowe parametry modelu", "type": { "description": "Wybierz typ modelu", @@ -710,7 +714,8 @@ "temperatureMin": "Temperatura musi być większa lub równa 0", "temperatureRequired": "Temperatura nie może być pusta", "timeoutMin": "Limit czasu żądania musi wynosić co najmniej 1000 ms", - "timeoutMax": "Limit czasu żądania nie może przekroczyć 3600000 ms" + "timeoutMax": "Limit czasu żądania nie może przekroczyć 3600000 ms", + "topPRange": "Top P must be greater than 0 and less than or equal to 1" }, "vision": { "description": "Czy model obsługuje zdolności wizualne?", diff --git a/src/renderer/src/i18n/pt-BR/chat.json b/src/renderer/src/i18n/pt-BR/chat.json index 97b3eef12..c41f4463a 100644 --- a/src/renderer/src/i18n/pt-BR/chat.json +++ b/src/renderer/src/i18n/pt-BR/chat.json @@ -166,6 +166,8 @@ "systemPromptPlaceholder": "Selecione um preset", "temperature": "Temperatura", "temperatureFixedMoonshotKimi": "Moonshot Kimi K2.5/K2.6 fixa a temperatura em {enabled} quando o modo de pensamento está ativado e em {disabled} quando está desativado.", + "topP": "Top P", + "topPDescription": "Amostragem nucleus; deixe em branco para usar o padrão do provedor", "contextLength": "Tamanho do contexto", "maxTokens": "Máx. de tokens", "thinkingBudget": "Orçamento de raciocínio", @@ -182,7 +184,8 @@ "finiteNumber": "Deve ser um número finito", "nonNegativeInteger": "Deve ser um inteiro não negativo", "contextLengthAtLeastMaxTokens": "Deve ser maior ou igual ao Máximo de saída", - "maxTokensWithinContextLength": "Deve ser menor ou igual ao Tamanho de contexto" + "maxTokensWithinContextLength": "Deve ser menor ou igual ao Tamanho de contexto", + "topPRange": "Deve ser maior que 0 e menor ou igual a 1" } }, "workspace": { diff --git a/src/renderer/src/i18n/pt-BR/settings.json b/src/renderer/src/i18n/pt-BR/settings.json index df2c402dd..4dabec081 100644 --- a/src/renderer/src/i18n/pt-BR/settings.json +++ b/src/renderer/src/i18n/pt-BR/settings.json @@ -624,6 +624,10 @@ "fixedMoonshotKimi": "Moonshot Kimi K2.5/K2.6 fixa a temperatura em {enabled} quando o modo de pensamento está ativado e em {disabled} quando está desativado.", "label": "Temperatura" }, + "topP": { + "label": "Top P", + "description": "Controla a amostragem nucleus. Deixe em branco para usar o padrão do modelo ou provedor." + }, "title": "Parâmetros personalizados do modelo", "type": { "description": "Selecionar o tipo de modelo", @@ -647,7 +651,8 @@ "temperatureMin": "A temperatura deve ser maior ou igual a 0", "temperatureRequired": "A temperatura não pode estar vazia", "timeoutMin": "O tempo limite da solicitação deve ser de pelo menos 1000ms", - "timeoutMax": "O tempo limite da solicitação não pode exceder 3600000ms" + "timeoutMax": "O tempo limite da solicitação não pode exceder 3600000ms", + "topPRange": "Top P deve ser maior que 0 e menor ou igual a 1" }, "vision": { "description": "O modelo suporta capacidade visual?", diff --git a/src/renderer/src/i18n/ru-RU/chat.json b/src/renderer/src/i18n/ru-RU/chat.json index 167c4c329..e24d42d65 100644 --- a/src/renderer/src/i18n/ru-RU/chat.json +++ b/src/renderer/src/i18n/ru-RU/chat.json @@ -166,6 +166,8 @@ "systemPromptPlaceholder": "Выберите пресет", "temperature": "Температура", "temperatureFixedMoonshotKimi": "Moonshot Kimi K2.5/K2.6 фиксирует температуру на уровне {enabled}, когда мышление включено, и на уровне {disabled}, когда оно отключено.", + "topP": "Top P", + "topPDescription": "Nucleus sampling; оставьте пустым, чтобы использовать значение провайдера по умолчанию", "contextLength": "Длина контекста", "maxTokens": "Макс. токенов", "thinkingBudget": "Бюджет размышления", @@ -182,7 +184,8 @@ "finiteNumber": "Должно быть конечным числом", "nonNegativeInteger": "Должно быть неотрицательным целым числом", "contextLengthAtLeastMaxTokens": "Должно быть больше или равно максимальному числу токенов", - "maxTokensWithinContextLength": "Должно быть меньше или равно длине контекста" + "maxTokensWithinContextLength": "Должно быть меньше или равно длине контекста", + "topPRange": "Должно быть больше 0 и меньше либо равно 1" } }, "workspace": { diff --git a/src/renderer/src/i18n/ru-RU/settings.json b/src/renderer/src/i18n/ru-RU/settings.json index 0a49ec7af..02ab64a7a 100644 --- a/src/renderer/src/i18n/ru-RU/settings.json +++ b/src/renderer/src/i18n/ru-RU/settings.json @@ -624,6 +624,10 @@ "fixedMoonshotKimi": "Moonshot Kimi K2.5/K2.6 фиксирует температуру на уровне {enabled}, когда мышление включено, и на уровне {disabled}, когда оно отключено.", "label": "температура" }, + "topP": { + "label": "Top P", + "description": "Управляет nucleus sampling. Оставьте пустым, чтобы использовать значение модели или провайдера по умолчанию." + }, "title": "Пользовательские параметры модели", "type": { "description": "Выберите тип модели", @@ -647,7 +651,8 @@ "temperatureMin": "Температура должна быть больше или равна 0", "temperatureRequired": "Температура не может быть пустой", "timeoutMin": "Тайм-аут запроса должен быть не менее 1000ms", - "timeoutMax": "Тайм-аут запроса не может превышать 3600000ms" + "timeoutMax": "Тайм-аут запроса не может превышать 3600000ms", + "topPRange": "Top P должно быть больше 0 и меньше либо равно 1" }, "vision": { "description": "Поддерживает ли модель визуальные способности?", diff --git a/src/renderer/src/i18n/tr-TR/chat.json b/src/renderer/src/i18n/tr-TR/chat.json index 65a3ab7c4..e2245b1bb 100644 --- a/src/renderer/src/i18n/tr-TR/chat.json +++ b/src/renderer/src/i18n/tr-TR/chat.json @@ -177,6 +177,8 @@ "systemPromptPlaceholder": "Bir ön ayar seçin", "temperature": "Sıcaklık", "temperatureFixedMoonshotKimi": "Moonshot Kimi K2.5/K2.6, düşünme etkinleştirildiğinde sıcaklığı {enabled}'ye ve devre dışı bırakıldığında {disabled}'ye sabitler.", + "topP": "Top P", + "topPDescription": "Nucleus örnekleme; sağlayıcı varsayılanını kullanmak için boş bırakın", "contextLength": "Bağlam Uzunluğu", "maxTokens": "Maksimum token", "thinkingBudget": "Thinking Budget", @@ -193,7 +195,8 @@ "finiteNumber": "Sonlu bir sayı olmalı", "nonNegativeInteger": "Negatif olmayan bir tam sayı olmalıdır", "contextLengthAtLeastMaxTokens": "Maksimum token değerinden büyük veya ona eşit olmalıdır", - "maxTokensWithinContextLength": "Bağlam Uzunluğundan küçük veya ona eşit olmalıdır" + "maxTokensWithinContextLength": "Bağlam Uzunluğundan küçük veya ona eşit olmalıdır", + "topPRange": "0’dan büyük ve 1’e eşit ya da küçük olmalıdır" } }, "modelPicker": { diff --git a/src/renderer/src/i18n/tr-TR/settings.json b/src/renderer/src/i18n/tr-TR/settings.json index ccc6d226e..335b5f8e1 100644 --- a/src/renderer/src/i18n/tr-TR/settings.json +++ b/src/renderer/src/i18n/tr-TR/settings.json @@ -623,6 +623,10 @@ "description": "Çıktının rastgeleliğini kontrol edin. Çoğu model 0-1'dir ve bazıları 0-2 arasındadır. Daha yüksek değerler rastgeleliği artırır.", "fixedMoonshotKimi": "Moonshot Kimi K2.5/K2.6, düşünme etkinleştirildiğinde sıcaklığı {enabled}'ye ve devre dışı bırakıldığında {disabled}'ye sabitler." }, + "topP": { + "label": "Top P", + "description": "Nucleus örneklemeyi kontrol eder. Model veya sağlayıcı varsayılanını kullanmak için boş bırakın." + }, "vision": { "label": "Görsel yetenek", "description": "Model görsel yeteneği destekliyor mu?" @@ -723,7 +727,8 @@ "temperatureMin": "Sıcaklık 0'dan büyük veya ona eşit olmalıdır", "temperatureMax": "Sıcaklık 2'ye eşit veya daha az olmalıdır", "timeoutMin": "İstek zaman aşımı en az 1000 ms olmalıdır", - "timeoutMax": "İstek zaman aşımı 3600000 ms'yi aşamaz" + "timeoutMax": "İstek zaman aşımı 3600000 ms'yi aşamaz", + "topPRange": "Top P 0’dan büyük ve 1’e eşit ya da küçük olmalıdır" }, "endpointType": { "label": "Uç Nokta Türü", diff --git a/src/renderer/src/i18n/vi-VN/chat.json b/src/renderer/src/i18n/vi-VN/chat.json index f045d7318..0dc9765d6 100644 --- a/src/renderer/src/i18n/vi-VN/chat.json +++ b/src/renderer/src/i18n/vi-VN/chat.json @@ -177,6 +177,8 @@ "systemPromptPlaceholder": "Chọn một cài đặt trước", "temperature": "Nhiệt độ", "temperatureFixedMoonshotKimi": "Moonshot Kimi K2.5/K2.6 sửa nhiệt độ thành {enabled} khi tính năng suy nghĩ được bật và {disabled} khi tính năng này bị tắt.", + "topP": "Top P", + "topPDescription": "Nucleus sampling; leave blank to use provider default", "contextLength": "Độ dài ngữ cảnh", "maxTokens": "Tối đa Tokens", "thinkingBudget": "Suy nghĩ về ngân sách", @@ -193,7 +195,8 @@ "finiteNumber": "Phải là số hữu hạn", "nonNegativeInteger": "Phải là số nguyên không âm", "contextLengthAtLeastMaxTokens": "Phải lớn hơn hoặc bằng Max Tokens", - "maxTokensWithinContextLength": "Phải nhỏ hơn hoặc bằng Độ dài ngữ cảnh" + "maxTokensWithinContextLength": "Phải nhỏ hơn hoặc bằng Độ dài ngữ cảnh", + "topPRange": "Must be greater than 0 and less than or equal to 1" } }, "modelPicker": { diff --git a/src/renderer/src/i18n/vi-VN/settings.json b/src/renderer/src/i18n/vi-VN/settings.json index b5039e538..1499387a9 100644 --- a/src/renderer/src/i18n/vi-VN/settings.json +++ b/src/renderer/src/i18n/vi-VN/settings.json @@ -687,6 +687,10 @@ "fixedMoonshotKimi": "Moonshot Kimi K2.5/K2.6 sửa nhiệt độ thành {enabled} khi tính năng suy nghĩ được bật và {disabled} khi tính năng này bị tắt.", "label": "Nhiệt độ" }, + "topP": { + "label": "Top P", + "description": "Controls nucleus sampling. Leave blank to use the model or provider default." + }, "title": "Thông số mô hình tùy chỉnh", "type": { "description": "Chọn loại mô hình", @@ -710,7 +714,8 @@ "temperatureMin": "Nhiệt độ phải lớn hơn hoặc bằng 0", "temperatureRequired": "Nhiệt độ không thể trống", "timeoutMin": "Thời gian chờ yêu cầu phải ít nhất là 1000ms", - "timeoutMax": "Thời gian chờ yêu cầu không thể vượt quá 3600000ms" + "timeoutMax": "Thời gian chờ yêu cầu không thể vượt quá 3600000ms", + "topPRange": "Top P must be greater than 0 and less than or equal to 1" }, "vision": { "description": "Mô hình có hỗ trợ khả năng thị giác không?", diff --git a/src/renderer/src/i18n/zh-CN/chat.json b/src/renderer/src/i18n/zh-CN/chat.json index 9d624d5f8..0388b6f15 100644 --- a/src/renderer/src/i18n/zh-CN/chat.json +++ b/src/renderer/src/i18n/zh-CN/chat.json @@ -177,6 +177,8 @@ "systemPromptPlaceholder": "选择预设", "temperature": "温度", "temperatureFixedMoonshotKimi": "Moonshot Kimi K2.5/K2.6 在开启思考时固定为 {enabled},关闭思考时固定为 {disabled}。", + "topP": "Top P(核采样)", + "topPDescription": "留空使用服务商默认值", "contextLength": "上下文长度", "maxTokens": "最大输出", "thinkingBudget": "思考预算", @@ -193,7 +195,8 @@ "finiteNumber": "必须是有限数字", "nonNegativeInteger": "必须是非负整数", "contextLengthAtLeastMaxTokens": "必须大于或等于最大输出", - "maxTokensWithinContextLength": "必须小于或等于上下文长度" + "maxTokensWithinContextLength": "必须小于或等于上下文长度", + "topPRange": "必须大于 0 且小于或等于 1" } }, "modelPicker": { diff --git a/src/renderer/src/i18n/zh-CN/settings.json b/src/renderer/src/i18n/zh-CN/settings.json index 703163ca3..1879035a3 100644 --- a/src/renderer/src/i18n/zh-CN/settings.json +++ b/src/renderer/src/i18n/zh-CN/settings.json @@ -623,6 +623,10 @@ "description": "控制输出的随机性,大部分模型0-1,部分支持0-2之间,越高越随机", "fixedMoonshotKimi": "Moonshot Kimi K2.5/K2.6 在开启思考时固定为 {enabled},关闭思考时固定为 {disabled}。" }, + "topP": { + "label": "Top P(核采样)", + "description": "控制核采样范围。留空使用模型或服务商默认值。" + }, "vision": { "label": "视觉能力", "description": "模型是否支持视觉能力" @@ -723,7 +727,8 @@ "temperatureMin": "温度必须大于等于0", "temperatureMax": "温度必须小于等于2", "timeoutMin": "请求超时时间不能小于1000毫秒", - "timeoutMax": "请求超时时间不能超过3600000毫秒" + "timeoutMax": "请求超时时间不能超过3600000毫秒", + "topPRange": "Top P 必须大于 0 且小于或等于 1" }, "endpointType": { "label": "协议类型", diff --git a/src/renderer/src/i18n/zh-HK/chat.json b/src/renderer/src/i18n/zh-HK/chat.json index a7e95e462..fa1236f26 100644 --- a/src/renderer/src/i18n/zh-HK/chat.json +++ b/src/renderer/src/i18n/zh-HK/chat.json @@ -174,6 +174,8 @@ "systemPromptPlaceholder": "選擇預設", "temperature": "溫度", "temperatureFixedMoonshotKimi": "Moonshot Kimi K2.5/K2.6 在開啟思考時固定為 {enabled},關閉思考時固定為 {disabled}。", + "topP": "Top P", + "topPDescription": "Nucleus sampling; leave blank to use provider default", "contextLength": "上下文長度", "maxTokens": "最大輸出", "thinkingBudget": "思考預算", @@ -190,7 +192,8 @@ "finiteNumber": "必須是有限數字", "nonNegativeInteger": "必須是非負整數", "contextLengthAtLeastMaxTokens": "必須大於或等於最大輸出", - "maxTokensWithinContextLength": "必須小於或等於上下文長度" + "maxTokensWithinContextLength": "必須小於或等於上下文長度", + "topPRange": "Must be greater than 0 and less than or equal to 1" } }, "workspace": { diff --git a/src/renderer/src/i18n/zh-HK/settings.json b/src/renderer/src/i18n/zh-HK/settings.json index 7f0ee152a..07d58bbcb 100644 --- a/src/renderer/src/i18n/zh-HK/settings.json +++ b/src/renderer/src/i18n/zh-HK/settings.json @@ -624,6 +624,10 @@ "fixedMoonshotKimi": "Moonshot Kimi K2.5/K2.6 在開啟思考時固定為 {enabled},關閉思考時固定為 {disabled}。", "label": "溫度" }, + "topP": { + "label": "Top P", + "description": "Controls nucleus sampling. Leave blank to use the model or provider default." + }, "title": "自定義模型參數", "type": { "description": "選擇模型的類型", @@ -647,7 +651,8 @@ "temperatureMin": "溫度必須大於等於0", "temperatureRequired": "溫度不能為空", "timeoutMin": "請求逾時時間不能小於1000毫秒", - "timeoutMax": "請求逾時時間不能超過3600000毫秒" + "timeoutMax": "請求逾時時間不能超過3600000毫秒", + "topPRange": "Top P must be greater than 0 and less than or equal to 1" }, "vision": { "description": "模型是否支持視覺能力", diff --git a/src/renderer/src/i18n/zh-TW/chat.json b/src/renderer/src/i18n/zh-TW/chat.json index b27fa206d..2dac31591 100644 --- a/src/renderer/src/i18n/zh-TW/chat.json +++ b/src/renderer/src/i18n/zh-TW/chat.json @@ -174,6 +174,8 @@ "systemPromptPlaceholder": "選擇預設", "temperature": "溫度", "temperatureFixedMoonshotKimi": "Moonshot Kimi K2.5/K2.6 在開啟思考時固定為 {enabled},關閉思考時固定為 {disabled}。", + "topP": "Top P(核心採樣)", + "topPDescription": "留空使用服務商預設值", "contextLength": "上下文長度", "maxTokens": "最大輸出", "thinkingBudget": "思考預算", @@ -190,7 +192,8 @@ "finiteNumber": "必須是有限數字", "nonNegativeInteger": "必須是非負整數", "contextLengthAtLeastMaxTokens": "必須大於或等於最大輸出", - "maxTokensWithinContextLength": "必須小於或等於上下文長度" + "maxTokensWithinContextLength": "必須小於或等於上下文長度", + "topPRange": "必須大於 0 且小於或等於 1" } }, "workspace": { diff --git a/src/renderer/src/i18n/zh-TW/settings.json b/src/renderer/src/i18n/zh-TW/settings.json index a539e49ed..195bdf724 100644 --- a/src/renderer/src/i18n/zh-TW/settings.json +++ b/src/renderer/src/i18n/zh-TW/settings.json @@ -624,6 +624,10 @@ "fixedMoonshotKimi": "Moonshot Kimi K2.5/K2.6 在開啟思考時固定為 {enabled},關閉思考時固定為 {disabled}。", "label": "溫度" }, + "topP": { + "label": "Top P(核心採樣)", + "description": "控制核心採樣範圍。留空使用模型或服務商預設值。" + }, "title": "自定義模型參數", "type": { "description": "選擇模型的類型", @@ -647,7 +651,8 @@ "temperatureMin": "溫度必須大於等於0", "temperatureRequired": "溫度不能為空", "timeoutMin": "請求逾時時間不能小於1000毫秒", - "timeoutMax": "請求逾時時間不能超過3600000毫秒" + "timeoutMax": "請求逾時時間不能超過3600000毫秒", + "topPRange": "Top P 必須大於 0 且小於或等於 1" }, "vision": { "description": "模型是否支持視覺能力", diff --git a/src/renderer/src/pages/NewThreadPage.vue b/src/renderer/src/pages/NewThreadPage.vue index 08f11dac9..f4749aca2 100644 --- a/src/renderer/src/pages/NewThreadPage.vue +++ b/src/renderer/src/pages/NewThreadPage.vue @@ -861,6 +861,7 @@ const applyDraftDefaultsForSelectedAgent = async (): Promise => { draftStore.subagentEnabled = false draftStore.systemPrompt = undefined draftStore.temperature = undefined + draftStore.topP = undefined draftStore.contextLength = undefined draftStore.maxTokens = undefined draftStore.timeout = undefined diff --git a/src/renderer/src/stores/ui/draft.ts b/src/renderer/src/stores/ui/draft.ts index e958dd863..1efe15eb2 100644 --- a/src/renderer/src/stores/ui/draft.ts +++ b/src/renderer/src/stores/ui/draft.ts @@ -27,6 +27,7 @@ export const useDraftStore = defineStore('draft', () => { const agentId = ref('deepchat') const systemPrompt = ref(undefined) const temperature = ref(undefined) + const topP = ref(undefined) const contextLength = ref(undefined) const maxTokens = ref(undefined) const timeout = ref(undefined) @@ -68,6 +69,7 @@ export const useDraftStore = defineStore('draft', () => { if (systemPrompt.value !== undefined) settings.systemPrompt = systemPrompt.value if (temperature.value !== undefined) settings.temperature = temperature.value + if (topP.value !== undefined) settings.topP = topP.value if (contextLength.value !== undefined) settings.contextLength = contextLength.value if (maxTokens.value !== undefined) settings.maxTokens = maxTokens.value if (timeout.value !== undefined) settings.timeout = timeout.value @@ -113,6 +115,9 @@ export const useDraftStore = defineStore('draft', () => { if (Object.prototype.hasOwnProperty.call(settings, 'temperature')) { temperature.value = settings.temperature } + if (Object.prototype.hasOwnProperty.call(settings, 'topP')) { + topP.value = settings.topP + } if (Object.prototype.hasOwnProperty.call(settings, 'contextLength')) { contextLength.value = settings.contextLength } @@ -148,6 +153,7 @@ export const useDraftStore = defineStore('draft', () => { function resetGenerationSettings(): void { systemPrompt.value = undefined temperature.value = undefined + topP.value = undefined contextLength.value = undefined maxTokens.value = undefined timeout.value = undefined @@ -193,6 +199,7 @@ export const useDraftStore = defineStore('draft', () => { agentId, systemPrompt, temperature, + topP, contextLength, maxTokens, timeout, diff --git a/src/shared/contracts/common.ts b/src/shared/contracts/common.ts index 147032287..429a89cac 100644 --- a/src/shared/contracts/common.ts +++ b/src/shared/contracts/common.ts @@ -130,6 +130,7 @@ export const DeepChatSubagentMetaSchema = z export const SessionGenerationSettingsSchema = z.object({ systemPrompt: z.string(), temperature: z.number(), + topP: z.number().min(0.1).max(1).optional(), contextLength: z.number().int(), maxTokens: z.number().int(), timeout: z.number().int(), diff --git a/src/shared/contracts/domainSchemas.ts b/src/shared/contracts/domainSchemas.ts index 3bd230d8a..f0b024ad4 100644 --- a/src/shared/contracts/domainSchemas.ts +++ b/src/shared/contracts/domainSchemas.ts @@ -234,6 +234,7 @@ export const ModelConfigSchema = z maxTokens: z.number().int(), contextLength: z.number().int(), temperature: z.number().optional(), + topP: z.number().min(0.1).max(1).optional(), vision: z.boolean(), speechRecognition: z.boolean().optional(), functionCall: z.boolean(), diff --git a/src/shared/types/agent-interface.d.ts b/src/shared/types/agent-interface.d.ts index 5b9fe9118..782e22d80 100644 --- a/src/shared/types/agent-interface.d.ts +++ b/src/shared/types/agent-interface.d.ts @@ -24,6 +24,7 @@ export interface SessionCompactionState { export interface SessionGenerationSettings { systemPrompt: string temperature: number + topP?: number contextLength: number maxTokens: number timeout: number diff --git a/src/shared/types/presenters/legacy.presenters.d.ts b/src/shared/types/presenters/legacy.presenters.d.ts index 41541b997..5d75a4311 100644 --- a/src/shared/types/presenters/legacy.presenters.d.ts +++ b/src/shared/types/presenters/legacy.presenters.d.ts @@ -161,6 +161,7 @@ export interface ModelConfig { contextLength: number timeout?: number temperature?: number + topP?: number vision: boolean speechRecognition?: boolean functionCall: boolean diff --git a/src/shared/utils/generationSettingsValidation.ts b/src/shared/utils/generationSettingsValidation.ts index 10da40de8..64097d4e2 100644 --- a/src/shared/utils/generationSettingsValidation.ts +++ b/src/shared/utils/generationSettingsValidation.ts @@ -3,6 +3,7 @@ import type { SessionGenerationSettings } from '../types/agent-interface' export type GenerationNumericField = | 'temperature' + | 'topP' | 'contextLength' | 'maxTokens' | 'timeout' @@ -15,6 +16,7 @@ export type GenerationNumericValidationCode = | 'max_tokens_exceed_context_length' | 'timeout_too_small' | 'timeout_too_large' + | 'top_p_out_of_range' type GenerationRelationContext = Pick @@ -58,6 +60,13 @@ export const validateGenerationNumericField = ( return numeric === undefined ? 'finite_number' : null } + if (field === 'topP') { + if (numeric === undefined) { + return 'finite_number' + } + return numeric >= 0.1 && numeric <= 1 ? null : 'top_p_out_of_range' + } + if (!isNonNegativeInteger(numeric)) { return 'non_negative_integer' } diff --git a/src/types/i18n.d.ts b/src/types/i18n.d.ts index 8615ae91e..873043bdc 100644 --- a/src/types/i18n.d.ts +++ b/src/types/i18n.d.ts @@ -281,6 +281,8 @@ declare module 'vue-i18n' { systemPromptPlaceholder: string temperature: string temperatureFixedMoonshotKimi: string + topP: string + topPDescription: string contextLength: string maxTokens: string thinkingBudget: string @@ -298,6 +300,7 @@ declare module 'vue-i18n' { nonNegativeInteger: string contextLengthAtLeastMaxTokens: string maxTokensWithinContextLength: string + topPRange: string } } modelPicker: { diff --git a/test/main/presenter/sqlitePresenter/deepchatSessionsTable.test.ts b/test/main/presenter/sqlitePresenter/deepchatSessionsTable.test.ts index f7e5c5345..170f88c16 100644 --- a/test/main/presenter/sqlitePresenter/deepchatSessionsTable.test.ts +++ b/test/main/presenter/sqlitePresenter/deepchatSessionsTable.test.ts @@ -106,10 +106,11 @@ describe('DeepChatSessionsTable.updateSummaryStateIfMatches', () => { throw new Error(`Unexpected SQL: ${sql}`) }) - expect(table.getLatestVersion()).toBe(28) + expect(table.getLatestVersion()).toBe(29) expect(table.getMigrationSQL(23)).toBe( [ + 'ALTER TABLE deepchat_sessions ADD COLUMN top_p REAL;', 'ALTER TABLE deepchat_sessions ADD COLUMN timeout_ms INTEGER;', 'ALTER TABLE deepchat_sessions ADD COLUMN force_interleaved_thinking_compat INTEGER;', 'ALTER TABLE deepchat_sessions ADD COLUMN reasoning_visibility TEXT;', @@ -127,6 +128,11 @@ describe('DeepChatSessionsTable.updateSummaryStateIfMatches', () => { expect(table.getMigrationSQL(28)).toBe( 'ALTER TABLE deepchat_sessions ADD COLUMN video_generation_options_json TEXT;' ) + expect(table.getMigrationSQL(29)).toBe('ALTER TABLE deepchat_sessions ADD COLUMN top_p REAL;') + + expect(table.getMigrationSQL(23)).toContain( + 'ALTER TABLE deepchat_sessions ADD COLUMN top_p REAL;' + ) }) it('reads image generation settings from persisted JSON', () => { @@ -140,6 +146,7 @@ describe('DeepChatSessionsTable.updateSummaryStateIfMatches', () => { permission_mode: 'full_access', system_prompt: null, temperature: null, + top_p: null, context_length: null, max_tokens: null, timeout_ms: null, @@ -227,7 +234,7 @@ describe('DeepChatSessionsTable.updateSummaryStateIfMatches', () => { if (sql === 'SELECT MAX(version) as version FROM schema_versions') { return { - get: () => ({ version: 29 }) + get: () => ({ version: 30 }) } } @@ -239,11 +246,11 @@ describe('DeepChatSessionsTable.updateSummaryStateIfMatches', () => { const guardedTable = new DeepChatSessionsTable(guardedDb) expect(() => guardedTable.createTable()).toThrow( - 'Recorded deepchat_sessions schema version 29 exceeds supported version 28.' + 'Recorded deepchat_sessions schema version 30 exceeds supported version 29.' ) expect(exec).not.toHaveBeenCalled() expect(errorSpy).toHaveBeenCalledWith( - 'Recorded deepchat_sessions schema version 29 exceeds supported version 28. Refusing to create table from a downgraded schema.' + 'Recorded deepchat_sessions schema version 30 exceeds supported version 29. Refusing to create table from a downgraded schema.' ) }) }) diff --git a/test/main/shared/generationSettingsValidation.test.ts b/test/main/shared/generationSettingsValidation.test.ts index ebf26c45a..562d76d23 100644 --- a/test/main/shared/generationSettingsValidation.test.ts +++ b/test/main/shared/generationSettingsValidation.test.ts @@ -17,3 +17,20 @@ describe('validateGenerationNumericField timeout bounds', () => { ) }) }) + +describe('validateGenerationNumericField topP bounds', () => { + it('accepts finite topP values in the supported range', () => { + expect(validateGenerationNumericField('topP', 0.1)).toBeNull() + expect(validateGenerationNumericField('topP', 1)).toBeNull() + expect(validateGenerationNumericField('topP', '0.5')).toBeNull() + }) + + it('rejects non-finite and out-of-range topP values', () => { + expect(validateGenerationNumericField('topP', '')).toBe('finite_number') + expect(validateGenerationNumericField('topP', Number.NaN)).toBe('finite_number') + expect(validateGenerationNumericField('topP', 0)).toBe('top_p_out_of_range') + expect(validateGenerationNumericField('topP', 0.01)).toBe('top_p_out_of_range') + expect(validateGenerationNumericField('topP', -0.1)).toBe('top_p_out_of_range') + expect(validateGenerationNumericField('topP', 1.01)).toBe('top_p_out_of_range') + }) +}) diff --git a/test/renderer/stores/draft.test.ts b/test/renderer/stores/draft.test.ts new file mode 100644 index 000000000..3cbe9173e --- /dev/null +++ b/test/renderer/stores/draft.test.ts @@ -0,0 +1,34 @@ +import { beforeEach, describe, expect, it, vi } from 'vitest' + +describe('draft store generation settings', () => { + beforeEach(() => { + vi.resetModules() + vi.doMock('pinia', async () => { + const actual = await vi.importActual('pinia') + return actual + }) + }) + + it('includes topP overrides in new session input', async () => { + const { setActivePinia, createPinia } = await import('pinia') + setActivePinia(createPinia()) + const { useDraftStore } = await import('@/stores/ui/draft') + const draftStore = useDraftStore() + + draftStore.updateGenerationSettings({ topP: 0.72 }) + + expect(draftStore.toCreateInput('hello').generationSettings).toEqual({ topP: 0.72 }) + }) + + it('omits topP after clearing the override', async () => { + const { setActivePinia, createPinia } = await import('pinia') + setActivePinia(createPinia()) + const { useDraftStore } = await import('@/stores/ui/draft') + const draftStore = useDraftStore() + + draftStore.updateGenerationSettings({ topP: 0.72 }) + draftStore.updateGenerationSettings({ topP: undefined }) + + expect(draftStore.toCreateInput('hello').generationSettings).toBeUndefined() + }) +})