| ... | @@ -120,6 +120,10 @@ function getSelectedTraits( | ... | @@ -120,6 +120,10 @@ function getSelectedTraits( |
| 120 | caps.promptInjectedEffortLevels.length > 0 && | 120 | caps.promptInjectedEffortLevels.length > 0 && |
| 121 | isClaudeUltrathinkPrompt(prompt); | 121 | isClaudeUltrathinkPrompt(prompt); |
| 122 | | 122 | |
| | 123 | // Check if "ultrathink" appears in the body text (not just our prefix) |
| | 124 | const ultrathinkInBodyText = |
| | 125 | ultrathinkPromptControlled && isClaudeUltrathinkPrompt(prompt.replace(/^Ultrathink:\s*/i, "")); |
| | 126 | |
| 123 | return { | 127 | return { |
| 124 | caps, | 128 | caps, |
| 125 | effort, | 129 | effort, |
| ... | @@ -130,6 +134,7 @@ function getSelectedTraits( | ... | @@ -130,6 +134,7 @@ function getSelectedTraits( |
| 130 | contextWindow, | 134 | contextWindow, |
| 131 | defaultContextWindow, | 135 | defaultContextWindow, |
| 132 | ultrathinkPromptControlled, | 136 | ultrathinkPromptControlled, |
| | 137 | ultrathinkInBodyText, |
| 133 | }; | 138 | }; |
| 134 | } | 139 | } |
| 135 | | 140 | |
| ... | @@ -176,12 +181,12 @@ export const TraitsMenuContent = memo(function TraitsMenuContentImpl({ | ... | @@ -176,12 +181,12 @@ export const TraitsMenuContent = memo(function TraitsMenuContentImpl({ |
| 176 | contextWindow, | 181 | contextWindow, |
| 177 | defaultContextWindow, | 182 | defaultContextWindow, |
| 178 | ultrathinkPromptControlled, | 183 | ultrathinkPromptControlled, |
| | 184 | ultrathinkInBodyText, |
| 179 | } = getSelectedTraits(provider, models, model, prompt, modelOptions, allowPromptInjectedEffort); | 185 | } = getSelectedTraits(provider, models, model, prompt, modelOptions, allowPromptInjectedEffort); |
| 180 | const defaultEffort = getDefaultEffort(caps); | 186 | const defaultEffort = getDefaultEffort(caps); |
| 181 | | 187 | |
| 182 | const handleEffortChange = useCallback( | 188 | const handleEffortChange = useCallback( |
| 183 | (value: string) => { | 189 | (value: string) => { |
| 184 | if (ultrathinkPromptControlled) return; | | |
| 185 | if (!value) return; | 190 | if (!value) return; |
| 186 | const nextOption = effortLevels.find((option) => option.value === value); | 191 | const nextOption = effortLevels.find((option) => option.value === value); |
| 187 | if (!nextOption) return; | 192 | if (!nextOption) return; |
| ... | @@ -193,6 +198,11 @@ export const TraitsMenuContent = memo(function TraitsMenuContentImpl({ | ... | @@ -193,6 +198,11 @@ export const TraitsMenuContent = memo(function TraitsMenuContentImpl({ |
| 193 | onPromptChange(nextPrompt); | 198 | onPromptChange(nextPrompt); |
| 194 | return; | 199 | return; |
| 195 | } | 200 | } |
| | 201 | if (ultrathinkInBodyText) return; |
| | 202 | if (ultrathinkPromptControlled) { |
| | 203 | const stripped = prompt.replace(/^Ultrathink:\s*/i, ""); |
| | 204 | onPromptChange(stripped); |
| | 205 | } |
| 196 | const effortKey = provider === "codex" ? "reasoningEffort" : "effort"; | 206 | const effortKey = provider === "codex" ? "reasoningEffort" : "effort"; |
| 197 | updateModelOptions( | 207 | updateModelOptions( |
| 198 | buildNextOptions(provider, modelOptions, { [effortKey]: nextOption.value }), | 208 | buildNextOptions(provider, modelOptions, { [effortKey]: nextOption.value }), |
| ... | @@ -200,6 +210,7 @@ export const TraitsMenuContent = memo(function TraitsMenuContentImpl({ | ... | @@ -200,6 +210,7 @@ export const TraitsMenuContent = memo(function TraitsMenuContentImpl({ |
| 200 | }, | 210 | }, |
| 201 | [ | 211 | [ |
| 202 | ultrathinkPromptControlled, | 212 | ultrathinkPromptControlled, |
| | 213 | ultrathinkInBodyText, |
| 203 | modelOptions, | 214 | modelOptions, |
| 204 | onPromptChange, | 215 | onPromptChange, |
| 205 | updateModelOptions, | 216 | updateModelOptions, |
| ... | @@ -220,17 +231,20 @@ export const TraitsMenuContent = memo(function TraitsMenuContentImpl({ | ... | @@ -220,17 +231,20 @@ export const TraitsMenuContent = memo(function TraitsMenuContentImpl({ |
| 220 | <> | 231 | <> |
| 221 | <MenuGroup> | 232 | <MenuGroup> |
| 222 | <div className="px-2 pt-1.5 pb-1 font-medium text-muted-foreground text-xs">Effort</div> | 233 | <div className="px-2 pt-1.5 pb-1 font-medium text-muted-foreground text-xs">Effort</div> |
| 223 | {ultrathinkPromptControlled ? ( | 234 | {ultrathinkInBodyText ? ( |
| 224 | <div className="px-2 pb-1.5 text-muted-foreground/80 text-xs"> | 235 | <div className="px-2 pb-1.5 text-muted-foreground/80 text-xs"> |
| 225 | Remove Ultrathink from the prompt to change effort. | 236 | Your prompt contains &quot;ultrathink&quot; in the text. Remove it to change effort. |
| 226 | </div> | 237 | </div> |
| 227 | ) : null} | 238 | ) : null} |
| 228 | <MenuRadioGroup value={effort} onValueChange={handleEffortChange}> | 239 | <MenuRadioGroup |
| | 240 | value={ultrathinkPromptControlled ? "ultrathink" : effort} |
| | 241 | onValueChange={handleEffortChange} |
| | 242 | > |
| 229 | {effortLevels.map((option) => ( | 243 | {effortLevels.map((option) => ( |
| 230 | <MenuRadioItem | 244 | <MenuRadioItem |
| 231 | key={option.value} | 245 | key={option.value} |
| 232 | value={option.value} | 246 | value={option.value} |
| 233 | disabled={ultrathinkPromptControlled} | 247 | disabled={ultrathinkInBodyText} |
| 234 | > | 248 | > |
| 235 | {option.label} | 249 | {option.label} |
| 236 | {option.value === defaultEffort ? " (default)" : ""} | 250 | {option.value === defaultEffort ? " (default)" : ""} |