fix(reasoning): apply explicit per-call levels without runner config caching

This commit is contained in:
RockChinQ
2026-09-19 00:05:10 +08:00
parent da4b0d6ca2
commit 79cac0c6a3
24 changed files with 262 additions and 427 deletions
@@ -1,3 +1,4 @@
import { hasModelReasoningAbility } from '@/app/home/components/reasoning/model-reasoning';
import {
DynamicFormItemType,
IDynamicFormItemSchema,
@@ -193,8 +194,7 @@ export default function DynamicFormItemComponent({
{model.abilities?.includes('func_call') && (
<Wrench className="h-3 w-3 text-muted-foreground" />
)}
{(model.reasoning_capabilities?.supported === true ||
model.abilities?.includes('reasoning')) && (
{hasModelReasoningAbility(model) && (
<BrainCircuit
className="h-3 w-3 shrink-0 text-muted-foreground"
aria-label={t('models.reasoningAbility')}
@@ -1260,15 +1260,11 @@ export default function DynamicFormItemComponent({
const updateModelReasoning = (
modelUuid: string,
level: ReasoningLevel | undefined,
level: ReasoningLevel,
) => {
if (!modelUuid) return;
const updated = { ...modelValue.reasoning };
if (level === undefined) {
delete updated[modelUuid];
} else {
updated[modelUuid] = level;
}
updated[modelUuid] = level;
updateValue({ reasoning: updated });
};
@@ -1297,6 +1293,7 @@ export default function DynamicFormItemComponent({
const model = llmModels.find(
(candidate) => candidate.uuid === modelUuid,
);
if (!hasModelReasoningAbility(model)) return null;
const currentLevel =
modelValue.reasoning[modelUuid] || 'provider_default';
const availableLevels = model?.reasoning_capabilities?.levels || [
@@ -1310,8 +1307,6 @@ export default function DynamicFormItemComponent({
<ReasoningLevelPicker
value={currentLevel}
levels={levels}
inherited={!Object.hasOwn(modelValue.reasoning, modelUuid)}
onInherit={() => updateModelReasoning(modelUuid, undefined)}
onChange={(level) => updateModelReasoning(modelUuid, level)}
/>
);
@@ -1,3 +1,4 @@
import { hasModelReasoningAbility } from '../../reasoning/model-reasoning';
import { useState, useEffect } from 'react';
import { Trash2, Eye, Wrench, Check, BrainCircuit } from 'lucide-react';
import { Button } from '@/components/ui/button';
@@ -175,8 +176,7 @@ export default function ModelItem({
const supportsReasoning =
modelType === 'llm' &&
((model as LLMModel).reasoning_capabilities?.supported === true ||
(model as LLMModel).abilities?.includes('reasoning'));
hasModelReasoningAbility(model as LLMModel, isLangBotModels);
const canSaveModel = !isLangBotModels;
// Check if popover should be disabled (space models when not logged in)
@@ -353,7 +353,11 @@ export default function ModelItem({
<div className="flex items-center gap-2">
<Checkbox
id={`edit-reasoning-${model.uuid}`}
checked={editAbilities.includes('reasoning')}
checked={
isLangBotModels
? supportsReasoning
: editAbilities.includes('reasoning')
}
disabled={isLangBotModels}
onCheckedChange={(checked) =>
toggleAbility('reasoning', checked as boolean)
@@ -37,8 +37,6 @@ interface ReasoningLevelPickerProps {
value: ReasoningLevel;
levels: ReasoningLevel[];
disabled?: boolean;
inherited?: boolean;
onInherit?: () => void;
onChange: (value: ReasoningLevel) => void;
}
@@ -46,8 +44,6 @@ export default function ReasoningLevelPicker({
value,
levels,
disabled = false,
inherited = false,
onInherit,
onChange,
}: ReasoningLevelPickerProps) {
const { t } = useTranslation();
@@ -56,14 +52,8 @@ export default function ReasoningLevelPicker({
const safeValue: ReasoningLevel = safeLevels.includes(value)
? value
: safeLevels[0];
const isInherited = Boolean(onInherit && inherited);
const currentLabel = t(
isInherited
? 'models.reasoningLevels.useModelSetting'
: REASONING_LEVEL_LABEL_KEYS[safeValue],
);
const isExplicit =
!isInherited && (Boolean(onInherit) || safeValue !== 'provider_default');
const currentLabel = t(REASONING_LEVEL_LABEL_KEYS[safeValue]);
const isExplicit = safeValue !== 'provider_default';
const currentIndex = Math.max(0, safeLevels.indexOf(safeValue));
return (
@@ -73,9 +63,9 @@ export default function ReasoningLevelPicker({
type="button"
variant="outline"
size="sm"
disabled={disabled || (safeLevels.length <= 1 && !onInherit)}
disabled={disabled || safeLevels.length <= 1}
aria-label={`${t('models.reasoningLevel')}: ${currentLabel}`}
className="h-9 w-9 shrink-0 gap-1.5 px-2.5 text-xs font-normal sm:w-auto sm:max-w-36"
className="h-9 w-9 shrink-0 gap-1.5 px-2.5 text-xs font-normal sm:w-auto sm:max-w-52"
>
<BrainCircuit
className={`size-4 shrink-0 ${isExplicit ? 'text-primary' : 'text-muted-foreground'}`}
@@ -87,29 +77,17 @@ export default function ReasoningLevelPicker({
</Button>
</PopoverTrigger>
<PopoverContent align="end" className="w-[272px] p-4">
{onInherit && (
<div className="mb-3 flex flex-col gap-1">
<Button
type="button"
variant="outline"
size="sm"
aria-pressed={isInherited}
onClick={onInherit}
>
{t('models.reasoningLevels.useModelSetting')}
</Button>
{safeLevels.includes('provider_default') && (
<Button
type="button"
variant="outline"
size="sm"
aria-pressed={!isInherited && safeValue === 'provider_default'}
onClick={() => onChange('provider_default')}
>
{t(REASONING_LEVEL_LABEL_KEYS.provider_default)}
</Button>
)}
</div>
{safeLevels.includes('provider_default') && (
<Button
type="button"
variant="outline"
size="sm"
className="mb-3 w-full"
aria-pressed={safeValue === 'provider_default'}
onClick={() => onChange('provider_default')}
>
{t(REASONING_LEVEL_LABEL_KEYS.provider_default)}
</Button>
)}
<div className="flex h-5 items-center gap-0.5 text-sm text-muted-foreground">
<span>{currentLabel}</span>
@@ -0,0 +1,18 @@
import { LANGBOT_MODELS_PROVIDER_REQUESTER } from '../models-dialog/types';
interface ModelReasoningInfo {
abilities?: string[];
reasoning_capabilities?: { supported?: boolean };
provider?: { requester?: string };
}
export function hasModelReasoningAbility(
model: ModelReasoningInfo | undefined,
isLangBotModels = model?.provider?.requester ===
LANGBOT_MODELS_PROVIDER_REQUESTER,
): boolean {
return Boolean(
model?.abilities?.includes('reasoning') ||
(isLangBotModels && model?.reasoning_capabilities?.supported === true),
);
}
+1 -2
View File
@@ -264,8 +264,7 @@ const enUS = {
reasoningAbility: 'Reasoning',
reasoningLevel: 'Reasoning level',
reasoningLevels: {
useModelSetting: 'Use model setting',
providerDefault: 'Provider default',
providerDefault: 'Use provider default',
disabled: 'Off',
enabled: 'On',
minimal: 'Minimal',
+1 -2
View File
@@ -265,8 +265,7 @@ const esES = {
reasoningAbility: 'Razonamiento',
reasoningLevel: 'Nivel de razonamiento',
reasoningLevels: {
useModelSetting: 'Usar ajuste del modelo',
providerDefault: 'Predeterminado del proveedor',
providerDefault: 'Usar valor predeterminado del proveedor',
disabled: 'Desactivado',
enabled: 'Activado',
minimal: 'Mínimo',
+1 -2
View File
@@ -269,8 +269,7 @@ const jaJP = {
reasoningAbility: '推論',
reasoningLevel: '推論レベル',
reasoningLevels: {
useModelSetting: 'モデル設定を使用',
providerDefault: 'Provider デフォルト',
providerDefault: 'プロバイダーの既定値を使用',
disabled: 'オフ',
enabled: 'オン',
minimal: '最小',
+1 -2
View File
@@ -261,8 +261,7 @@ const ruRU = {
reasoningAbility: 'Рассуждение',
reasoningLevel: 'Уровень рассуждений',
reasoningLevels: {
useModelSetting: 'Настройка модели',
providerDefault: 'По умолчанию провайдера',
providerDefault: 'Использовать настройки поставщика',
disabled: 'Выключено',
enabled: 'Включено',
minimal: 'Минимальный',
+1 -2
View File
@@ -256,8 +256,7 @@ const thTH = {
reasoningAbility: 'ความสามารถในการให้เหตุผล',
reasoningLevel: 'ระดับการให้เหตุผล',
reasoningLevels: {
useModelSetting: 'ใช้การตั้งค่าโมเดล',
providerDefault: 'ค่าเริ่มต้นของผู้ให้บริการ',
providerDefault: 'ใช้ค่าเริ่มต้นของผู้ให้บริการ',
disabled: 'ปิด',
enabled: 'เปิด',
minimal: 'ต่ำสุด',
+1 -2
View File
@@ -260,8 +260,7 @@ const viVN = {
reasoningAbility: 'Khả năng suy luận',
reasoningLevel: 'Mức độ suy luận',
reasoningLevels: {
useModelSetting: 'Dùng cài đặt mô hình',
providerDefault: 'Mặc định của nhà cung cấp',
providerDefault: 'Dùng giá trị mặc định của nhà cung cấp',
disabled: 'Tắt',
enabled: 'Bật',
minimal: 'Tối thiểu',
+1 -2
View File
@@ -254,8 +254,7 @@ const zhHans = {
reasoningAbility: '思考能力',
reasoningLevel: '思考档位',
reasoningLevels: {
useModelSetting: '使用模型设置',
providerDefault: 'Provider 默认',
providerDefault: '使用供应商默认值',
disabled: '关闭',
enabled: '开启',
minimal: '最低',
+1 -2
View File
@@ -248,8 +248,7 @@ const zhHant = {
reasoningAbility: '思考能力',
reasoningLevel: '思考等級',
reasoningLevels: {
useModelSetting: '使用模型設定',
providerDefault: '供應商預設',
providerDefault: '使用供應商預設值',
disabled: '關閉',
enabled: '開啟',
minimal: '最低',