@@ -11,7 +11,10 @@ import {
1111 clampEffort ,
1212 pickEffortFromCascade ,
1313 resolveEffortForRole ,
14+ defaultEffortForModel ,
15+ resolveSessionEffort ,
1416} from "./reasoning-effort.js" ;
17+ import { composePromptActionBarModelLabel } from "../tui/components/prompt-action-bar-label.js" ;
1518
1619describe ( "REASONING_EFFORTS" , ( ) => {
1720 test ( "is ordered from least to most effort" , ( ) => {
@@ -120,15 +123,41 @@ describe("cycleReasoningEffort", () => {
120123 afterEach ( ( ) => setModelReasoningCapabilities ( { } ) ) ;
121124
122125 test ( "walks the gpt-5 ladder and wraps" , ( ) => {
123- expect ( cycleReasoningEffort ( "gpt-5" , undefined ) ) . toBe ( "minimal" ) ;
124126 expect ( cycleReasoningEffort ( "gpt-5" , "minimal" ) ) . toBe ( "low" ) ;
125127 expect ( cycleReasoningEffort ( "gpt-5" , "low" ) ) . toBe ( "medium" ) ;
126128 expect ( cycleReasoningEffort ( "gpt-5" , "medium" ) ) . toBe ( "high" ) ;
127129 expect ( cycleReasoningEffort ( "gpt-5" , "high" ) ) . toBe ( "minimal" ) ;
128130 } ) ;
129131
130- test ( "starts at the first supported level when current is unsupported" , ( ) => {
131- expect ( cycleReasoningEffort ( "gpt-5" , "xhigh" ) ) . toBe ( "minimal" ) ;
132+ test ( "unset gpt-5 cycles from the implicit medium default to high" , ( ) => {
133+ expect ( cycleReasoningEffort ( "gpt-5" , undefined ) ) . toBe ( "high" ) ;
134+ } ) ;
135+
136+ test ( "unset grok cycles from implicit high, matching an explicit high" , ( ) => {
137+ expect ( cycleReasoningEffort ( "grok-4.6" , undefined ) ) . toBe (
138+ cycleReasoningEffort ( "grok-4.6" , "high" ) ,
139+ ) ;
140+ expect ( cycleReasoningEffort ( "grok-4.6" , "high" ) ) . toBe ( "low" ) ;
141+ } ) ;
142+
143+ test ( "unset gpt-5.1 chat cycles from implicit none to minimal" , ( ) => {
144+ expect ( cycleReasoningEffort ( "gpt-5.1" , undefined ) ) . toBe ( "minimal" ) ;
145+ } ) ;
146+
147+ test ( "leftover unsupported effort cycles from the family default" , ( ) => {
148+ expect ( cycleReasoningEffort ( "gpt-5" , "xhigh" ) ) . toBe ( "high" ) ;
149+ expect ( cycleReasoningEffort ( "gpt-5" , "xhigh" ) ) . toBe ( cycleReasoningEffort ( "gpt-5" , "medium" ) ) ;
150+ } ) ;
151+
152+ test ( "grok leftover minimal cycles the same as unset / high" , ( ) => {
153+ expect ( cycleReasoningEffort ( "grok-4.6" , "minimal" ) ) . toBe ( cycleReasoningEffort ( "grok-4.6" , undefined ) ) ;
154+ expect ( cycleReasoningEffort ( "grok-4.6" , "minimal" ) ) . toBe ( cycleReasoningEffort ( "grok-4.6" , "high" ) ) ;
155+ expect ( cycleReasoningEffort ( "grok-4.6" , "minimal" ) ) . toBe ( "low" ) ;
156+ } ) ;
157+
158+ test ( "unknown models with rungs still start at supported[0] when no default exists" , ( ) => {
159+ expect ( defaultEffortForModel ( "some-random-model" ) ) . toBeUndefined ( ) ;
160+ expect ( cycleReasoningEffort ( "some-random-model" , undefined ) ) . toBe ( "low" ) ;
132161 } ) ;
133162
134163 test ( "returns undefined for a non-reasoning model" , ( ) => {
@@ -334,3 +363,88 @@ describe("resolveEffortForRole", () => {
334363 ) . toBe ( "high" ) ;
335364 } ) ;
336365} ) ;
366+
367+ describe ( "defaultEffortForModel" , ( ) => {
368+ afterEach ( ( ) => setModelReasoningCapabilities ( { } ) ) ;
369+
370+ test ( "grok family defaults to high" , ( ) => {
371+ expect ( defaultEffortForModel ( "grok-4.6" ) ) . toBe ( "high" ) ;
372+ expect ( defaultEffortForModel ( "grok-4.5" ) ) . toBe ( "high" ) ;
373+ } ) ;
374+
375+ test ( "gpt-5 and o-series default to medium" , ( ) => {
376+ expect ( defaultEffortForModel ( "gpt-5" ) ) . toBe ( "medium" ) ;
377+ expect ( defaultEffortForModel ( "o1" ) ) . toBe ( "medium" ) ;
378+ expect ( defaultEffortForModel ( "o3-mini" ) ) . toBe ( "medium" ) ;
379+ expect ( defaultEffortForModel ( "o4-mini" ) ) . toBe ( "medium" ) ;
380+ } ) ;
381+
382+ test ( "gpt-5.1 chat defaults to none when none is on the ladder" , ( ) => {
383+ expect ( supportedEfforts ( "gpt-5.1" ) . includes ( "none" ) ) . toBe ( true ) ;
384+ expect ( defaultEffortForModel ( "gpt-5.1" ) ) . toBe ( "none" ) ;
385+ expect ( defaultEffortForModel ( "gpt-5.1" , false ) ) . toBe ( "none" ) ;
386+ } ) ;
387+
388+ test ( "Codex defaults to medium" , ( ) => {
389+ expect ( defaultEffortForModel ( "gpt-5.6-sol" , true ) ) . toBe ( "medium" ) ;
390+ expect ( defaultEffortForModel ( "gpt-5.1-codex" , true ) ) . toBe ( "medium" ) ;
391+ } ) ;
392+
393+ test ( "empty ladder yields undefined" , ( ) => {
394+ setModelReasoningCapabilities ( { "chat-only-model" : false } ) ;
395+ expect ( defaultEffortForModel ( "chat-only-model" ) ) . toBeUndefined ( ) ;
396+ } ) ;
397+
398+ test ( "unknown models with rungs have no family default" , ( ) => {
399+ expect ( supportedEfforts ( "some-random-model" ) . length ) . toBeGreaterThan ( 0 ) ;
400+ expect ( defaultEffortForModel ( "some-random-model" ) ) . toBeUndefined ( ) ;
401+ } ) ;
402+ } ) ;
403+
404+ describe ( "resolveSessionEffort" , ( ) => {
405+ afterEach ( ( ) => setModelReasoningCapabilities ( { } ) ) ;
406+
407+ test ( "empty ladder yields undefined even when configured" , ( ) => {
408+ setModelReasoningCapabilities ( { "chat-only-model" : false } ) ;
409+ expect ( resolveSessionEffort ( "chat-only-model" , "high" ) ) . toBeUndefined ( ) ;
410+ } ) ;
411+
412+ test ( "keeps a supported configured level" , ( ) => {
413+ expect ( resolveSessionEffort ( "gpt-5" , "low" ) ) . toBe ( "low" ) ;
414+ expect ( resolveSessionEffort ( "grok-4.6" , "low" ) ) . toBe ( "low" ) ;
415+ } ) ;
416+
417+ test ( "falls back to the family default when unset or unsupported" , ( ) => {
418+ expect ( resolveSessionEffort ( "gpt-5" , undefined ) ) . toBe ( "medium" ) ;
419+ expect ( resolveSessionEffort ( "gpt-5" , "xhigh" ) ) . toBe ( "medium" ) ;
420+ expect ( resolveSessionEffort ( "grok-4.6" , undefined ) ) . toBe ( "high" ) ;
421+ expect ( resolveSessionEffort ( "gpt-5.1" , undefined ) ) . toBe ( "none" ) ;
422+ expect ( resolveSessionEffort ( "gpt-5.6-sol" , undefined , true ) ) . toBe ( "medium" ) ;
423+ expect ( resolveSessionEffort ( "some-random-model" , undefined ) ) . toBeUndefined ( ) ;
424+ } ) ;
425+ } ) ;
426+
427+ describe ( "prompt action bar effort label" , ( ) => {
428+ test ( "joiner stays a dumb concatenation of the resolved session effort" , ( ) => {
429+ const effort = resolveSessionEffort ( "grok-4.6" , undefined ) ;
430+ expect ( effort ) . toBe ( "high" ) ;
431+ expect (
432+ composePromptActionBarModelLabel ( {
433+ profile : "xai/work" ,
434+ model : "grok-4.6" ,
435+ ...( effort !== undefined ? { effort } : { } ) ,
436+ } ) ,
437+ ) . toBe ( "xai/work · grok-4.6 · high" ) ;
438+ } ) ;
439+
440+ test ( "shows gpt-5 medium without seeding a configured effort" , ( ) => {
441+ const effort = resolveSessionEffort ( "gpt-5" , undefined ) ;
442+ expect ( effort ) . toBe ( "medium" ) ;
443+ expect (
444+ composePromptActionBarModelLabel ( {
445+ model : "gpt-5" ,
446+ ...( effort !== undefined ? { effort } : { } ) ,
447+ } ) ,
448+ ) . toBe ( "gpt-5 · medium" ) ;
449+ } ) ;
450+ } ) ;
0 commit comments