From 2da2378ae39c8c74656887aaad37be1ed9801dae Mon Sep 17 00:00:00 2001 From: xintaofei Date: Wed, 15 Apr 2026 16:38:39 +0800 Subject: [PATCH] feat(settings): add reasoning effort level for Claude Code Add an Effort Level dropdown under the Claude Code model inputs with options Low / Medium / High / Max (Opus only). The selection writes an "effortLevel" key at the root of the Claude Code config JSON, and is removed when the default is chosen. Manual edits to the native JSON textarea stay in sync with the dropdown. --- .../settings/acp-agent-settings.tsx | 100 ++++++++++++++++++ src/i18n/messages/ar.json | 8 +- src/i18n/messages/de.json | 8 +- src/i18n/messages/en.json | 8 +- src/i18n/messages/es.json | 8 +- src/i18n/messages/fr.json | 8 +- src/i18n/messages/ja.json | 8 +- src/i18n/messages/ko.json | 8 +- src/i18n/messages/pt.json | 8 +- src/i18n/messages/zh-CN.json | 8 +- src/i18n/messages/zh-TW.json | 8 +- 11 files changed, 170 insertions(+), 10 deletions(-) diff --git a/src/components/settings/acp-agent-settings.tsx b/src/components/settings/acp-agent-settings.tsx index b336330..42a12ac 100644 --- a/src/components/settings/acp-agent-settings.tsx +++ b/src/components/settings/acp-agent-settings.tsx @@ -127,6 +127,7 @@ interface AgentDraft { claudeDefaultHaikuModel: string claudeDefaultSonnetModel: string claudeDefaultOpusModel: string + claudeEffortLevel: ClaudeEffortLevel codexAuthJsonText: string codexConfigTomlText: string openCodeAuthJsonText: string @@ -251,6 +252,28 @@ const CLAUDE_MODEL_ENV_KEYS = { claudeDefaultOpusModel: "ANTHROPIC_DEFAULT_OPUS_MODEL", } as const +const CLAUDE_EFFORT_LEVEL_CONFIG_KEY = "effortLevel" + +type ClaudeEffortLevel = "" | "low" | "medium" | "high" | "max" + +const CLAUDE_EFFORT_LEVEL_VALUES: ReadonlyArray< + Exclude +> = ["low", "medium", "high", "max"] + +function normalizeClaudeEffortLevel(value: unknown): ClaudeEffortLevel { + if (typeof value !== "string") return "" + const normalized = value.trim().toLowerCase() + if ( + normalized === "low" || + normalized === "medium" || + normalized === "high" || + normalized === "max" + ) { + return normalized + } + return "" +} + const GEMINI_AUTH_MODES = [ "custom", "login_google", @@ -473,6 +496,7 @@ function extractImportantConfigValues( claudeDefaultHaikuModel: string claudeDefaultSonnetModel: string claudeDefaultOpusModel: string + claudeEffortLevel: ClaudeEffortLevel configError: string | null } { const parseResult = parseConfigJsonText(configText) @@ -507,6 +531,11 @@ function extractImportantConfigValues( CLAUDE_MODEL_ENV_KEYS.claudeDefaultOpusModel, ]) + const claudeEffortLevel: ClaudeEffortLevel = + agentType === "claude_code" + ? normalizeClaudeEffortLevel(config[CLAUDE_EFFORT_LEVEL_CONFIG_KEY]) + : "" + return { apiBaseUrl: apiBaseUrl ?? "", apiKey: apiKey ?? "", @@ -520,6 +549,7 @@ function extractImportantConfigValues( agentType === "claude_code" ? claudeDefaultSonnetModel : "", claudeDefaultOpusModel: agentType === "claude_code" ? claudeDefaultOpusModel : "", + claudeEffortLevel, configError: parseResult.error, } } @@ -2318,6 +2348,7 @@ function buildAgentDraft(agent: AcpAgentInfo): AgentDraft { claudeDefaultHaikuModel: important.claudeDefaultHaikuModel, claudeDefaultSonnetModel: important.claudeDefaultSonnetModel, claudeDefaultOpusModel: important.claudeDefaultOpusModel, + claudeEffortLevel: important.claudeEffortLevel, codexAuthJsonText, codexConfigTomlText, openCodeAuthJsonText, @@ -3569,6 +3600,7 @@ export function AcpAgentSettings() { claudeDefaultHaikuModel: important.claudeDefaultHaikuModel, claudeDefaultSonnetModel: important.claudeDefaultSonnetModel, claudeDefaultOpusModel: important.claudeDefaultOpusModel, + claudeEffortLevel: important.claudeEffortLevel, })) }, [selectedAgent, selectedDraft, updateSelectedDraft] @@ -3607,6 +3639,41 @@ export function AcpAgentSettings() { [selectedAgent, selectedDraft, t, updateSelectedDraft] ) + const handleClaudeEffortLevelChange = useCallback( + (nextValue: ClaudeEffortLevel) => { + if ( + !selectedAgent || + !selectedDraft || + selectedAgent.agent_type !== "claude_code" + ) + return + const parsed = parseConfigJsonText(selectedDraft.configText) + if (parsed.error) { + toast.warning(t("warnings.nativeJsonRecoveredStructured")) + } + const config: Record = parsed.error + ? {} + : { ...parsed.config } + if (nextValue) { + config[CLAUDE_EFFORT_LEVEL_CONFIG_KEY] = nextValue + } else { + delete config[CLAUDE_EFFORT_LEVEL_CONFIG_KEY] + } + const nextConfigText = + Object.keys(config).length === 0 ? "" : JSON.stringify(config, null, 2) + setConfigErrors((prev) => ({ + ...prev, + [selectedAgent.agent_type]: null, + })) + updateSelectedDraft((current) => ({ + ...current, + claudeEffortLevel: nextValue, + configText: nextConfigText, + })) + }, + [selectedAgent, selectedDraft, t, updateSelectedDraft] + ) + const handleClaudeAuthModeChange = useCallback( (nextMode: ClaudeAuthMode) => { if ( @@ -7111,6 +7178,39 @@ supports_websockets = true`}

{t("modelHintDefault")}

+
+ + +
) : (
diff --git a/src/i18n/messages/ar.json b/src/i18n/messages/ar.json index 6bab716..afaec10 100644 --- a/src/i18n/messages/ar.json +++ b/src/i18n/messages/ar.json @@ -626,7 +626,13 @@ "reasoningModel": "نموذج الاستدلال (thinking)", "haikuDefaultModel": "نموذج Haiku الافتراضي", "sonnetDefaultModel": "نموذج Sonnet الافتراضي", - "opusDefaultModel": "نموذج Opus الافتراضي" + "opusDefaultModel": "نموذج Opus الافتراضي", + "effortLevel": "مستوى الاستدلال", + "effortLevelDefault": "المستوى الافتراضي", + "effortLevel_low": "منخفض", + "effortLevel_medium": "متوسط", + "effortLevel_high": "مرتفع", + "effortLevelMax": "الأقصى (Opus فقط)" }, "dialogs": { "confirmDeleteProvider": "حذف المزود {providerId}؟", diff --git a/src/i18n/messages/de.json b/src/i18n/messages/de.json index 34a3105..1edf053 100644 --- a/src/i18n/messages/de.json +++ b/src/i18n/messages/de.json @@ -626,7 +626,13 @@ "reasoningModel": "Reasoning-Modell (thinking)", "haikuDefaultModel": "Standard-Haiku-Modell", "sonnetDefaultModel": "Standard-Sonnet-Modell", - "opusDefaultModel": "Standard-Opus-Modell" + "opusDefaultModel": "Standard-Opus-Modell", + "effortLevel": "Reasoning-Stufe", + "effortLevelDefault": "Standardstufe", + "effortLevel_low": "Niedrig", + "effortLevel_medium": "Mittel", + "effortLevel_high": "Hoch", + "effortLevelMax": "Maximum (nur Opus)" }, "dialogs": { "confirmDeleteProvider": "Provider {providerId} löschen?", diff --git a/src/i18n/messages/en.json b/src/i18n/messages/en.json index 76f166d..02b01cc 100644 --- a/src/i18n/messages/en.json +++ b/src/i18n/messages/en.json @@ -626,7 +626,13 @@ "reasoningModel": "Reasoning Model (thinking)", "haikuDefaultModel": "Default Haiku Model", "sonnetDefaultModel": "Default Sonnet Model", - "opusDefaultModel": "Default Opus Model" + "opusDefaultModel": "Default Opus Model", + "effortLevel": "Reasoning Effort Level", + "effortLevelDefault": "Default Level", + "effortLevel_low": "Low", + "effortLevel_medium": "Medium", + "effortLevel_high": "High", + "effortLevelMax": "Max (Opus only)" }, "dialogs": { "confirmDeleteProvider": "Delete Provider {providerId}?", diff --git a/src/i18n/messages/es.json b/src/i18n/messages/es.json index 4be76b6..73bea2d 100644 --- a/src/i18n/messages/es.json +++ b/src/i18n/messages/es.json @@ -626,7 +626,13 @@ "reasoningModel": "Modelo de razonamiento (thinking)", "haikuDefaultModel": "Modelo Haiku predeterminado", "sonnetDefaultModel": "Modelo Sonnet predeterminado", - "opusDefaultModel": "Modelo Opus predeterminado" + "opusDefaultModel": "Modelo Opus predeterminado", + "effortLevel": "Nivel de razonamiento", + "effortLevelDefault": "Nivel predeterminado", + "effortLevel_low": "Bajo", + "effortLevel_medium": "Medio", + "effortLevel_high": "Alto", + "effortLevelMax": "Máximo (solo Opus)" }, "dialogs": { "confirmDeleteProvider": "¿Eliminar proveedor {providerId}?", diff --git a/src/i18n/messages/fr.json b/src/i18n/messages/fr.json index 0e00e51..afab12d 100644 --- a/src/i18n/messages/fr.json +++ b/src/i18n/messages/fr.json @@ -626,7 +626,13 @@ "reasoningModel": "Modèle de raisonnement (thinking)", "haikuDefaultModel": "Modèle Haiku par défaut", "sonnetDefaultModel": "Modèle Sonnet par défaut", - "opusDefaultModel": "Modèle Opus par défaut" + "opusDefaultModel": "Modèle Opus par défaut", + "effortLevel": "Niveau de raisonnement", + "effortLevelDefault": "Niveau par défaut", + "effortLevel_low": "Bas", + "effortLevel_medium": "Moyen", + "effortLevel_high": "Élevé", + "effortLevelMax": "Maximum (Opus uniquement)" }, "dialogs": { "confirmDeleteProvider": "Supprimer le provider {providerId} ?", diff --git a/src/i18n/messages/ja.json b/src/i18n/messages/ja.json index cf57b26..511228d 100644 --- a/src/i18n/messages/ja.json +++ b/src/i18n/messages/ja.json @@ -626,7 +626,13 @@ "reasoningModel": "推論モデル(thinking)", "haikuDefaultModel": "デフォルト Haiku モデル", "sonnetDefaultModel": "デフォルト Sonnet モデル", - "opusDefaultModel": "デフォルト Opus モデル" + "opusDefaultModel": "デフォルト Opus モデル", + "effortLevel": "推論レベル", + "effortLevelDefault": "デフォルトレベル", + "effortLevel_low": "低", + "effortLevel_medium": "中", + "effortLevel_high": "高", + "effortLevelMax": "最大(Opus のみ対応)" }, "dialogs": { "confirmDeleteProvider": "Provider {providerId} を削除しますか?", diff --git a/src/i18n/messages/ko.json b/src/i18n/messages/ko.json index 21961c5..28df103 100644 --- a/src/i18n/messages/ko.json +++ b/src/i18n/messages/ko.json @@ -626,7 +626,13 @@ "reasoningModel": "추론 모델 (thinking)", "haikuDefaultModel": "기본 Haiku 모델", "sonnetDefaultModel": "기본 Sonnet 모델", - "opusDefaultModel": "기본 Opus 모델" + "opusDefaultModel": "기본 Opus 모델", + "effortLevel": "추론 수준", + "effortLevelDefault": "기본 수준", + "effortLevel_low": "낮음", + "effortLevel_medium": "중간", + "effortLevel_high": "높음", + "effortLevelMax": "최고 (Opus만 지원)" }, "dialogs": { "confirmDeleteProvider": "Provider {providerId}를 삭제하시겠습니까?", diff --git a/src/i18n/messages/pt.json b/src/i18n/messages/pt.json index 9533a3b..bdbde64 100644 --- a/src/i18n/messages/pt.json +++ b/src/i18n/messages/pt.json @@ -626,7 +626,13 @@ "reasoningModel": "Modelo de raciocínio (thinking)", "haikuDefaultModel": "Modelo Haiku padrão", "sonnetDefaultModel": "Modelo Sonnet padrão", - "opusDefaultModel": "Modelo Opus padrão" + "opusDefaultModel": "Modelo Opus padrão", + "effortLevel": "Nível de raciocínio", + "effortLevelDefault": "Nível padrão", + "effortLevel_low": "Baixo", + "effortLevel_medium": "Médio", + "effortLevel_high": "Alto", + "effortLevelMax": "Máximo (apenas Opus)" }, "dialogs": { "confirmDeleteProvider": "Excluir o provedor {providerId}?", diff --git a/src/i18n/messages/zh-CN.json b/src/i18n/messages/zh-CN.json index aaa51c8..f1ebefa 100644 --- a/src/i18n/messages/zh-CN.json +++ b/src/i18n/messages/zh-CN.json @@ -626,7 +626,13 @@ "reasoningModel": "推理模型(thinking)", "haikuDefaultModel": "Haiku 默认模型", "sonnetDefaultModel": "Sonnet 默认模型", - "opusDefaultModel": "Opus 默认模型" + "opusDefaultModel": "Opus 默认模型", + "effortLevel": "推理级别", + "effortLevelDefault": "默认级别", + "effortLevel_low": "低", + "effortLevel_medium": "中", + "effortLevel_high": "高", + "effortLevelMax": "最高(仅 Opus 支持)" }, "dialogs": { "confirmDeleteProvider": "确认删除 Provider {providerId}?", diff --git a/src/i18n/messages/zh-TW.json b/src/i18n/messages/zh-TW.json index 2f710e2..767cd29 100644 --- a/src/i18n/messages/zh-TW.json +++ b/src/i18n/messages/zh-TW.json @@ -626,7 +626,13 @@ "reasoningModel": "推理模型(thinking)", "haikuDefaultModel": "Haiku 預設模型", "sonnetDefaultModel": "Sonnet 預設模型", - "opusDefaultModel": "Opus 預設模型" + "opusDefaultModel": "Opus 預設模型", + "effortLevel": "推理等級", + "effortLevelDefault": "預設等級", + "effortLevel_low": "低", + "effortLevel_medium": "中", + "effortLevel_high": "高", + "effortLevelMax": "最高(僅 Opus 支援)" }, "dialogs": { "confirmDeleteProvider": "確認刪除 Provider {providerId}?",