@@ -2,11 +2,19 @@ import {
22 DEFAULT_FREEBUFF_MODEL_ID ,
33 resolveAvailableFreebuffModel ,
44} from '@codebuff/common/constants/freebuff-models'
5+ import {
6+ getFreebucksInfo ,
7+ getFreebuffServerAccessTier ,
8+ getSubscriptionInfo ,
9+ } from '@codebuff/common/types/freebuff-session'
10+ import { getFreebuffModelPresets } from '@codebuff/common/util/freebuff-model-presets'
11+ import { getFreebuffModelMeter } from '@codebuff/common/util/freebuff-session-pools'
512import { create } from 'zustand'
613
714import { getFreebuffModelDirectory } from './freebuff-catalog-store'
815import {
916 loadFreebuffCatalogReasoningEfforts ,
17+ loadFreebuffModelKeyPreference ,
1018 loadFreebuffModelPreference ,
1119 loadFreebuffReasoningEfforts ,
1220 saveFreebuffCatalogReasoningEffort ,
@@ -15,6 +23,7 @@ import {
1523 saveFreebuffReasoningEffort ,
1624} from '../utils/settings'
1725
26+ import type { FreebuffSessionResponse } from '../types/freebuff-session'
1827import type { ReasoningEffort } from '@codebuff/common/constants/reasoning-effort'
1928
2029/**
@@ -46,6 +55,8 @@ import type { ReasoningEffort } from '@codebuff/common/constants/reasoning-effor
4655interface FreebuffModelStore {
4756 selectedModel : string
4857 setSelectedModel : ( model : string ) => void
58+ /** Until the user picks, the selection follows freebuffDefaultModelForSession. */
59+ hasExplicitPick : boolean
4960 /** Per-model effort overrides. A model absent from this map runs its catalog
5061 * default; see saveFreebuffReasoningEffort for why absence is the "default"
5162 * state rather than a stored null. */
@@ -56,12 +67,17 @@ interface FreebuffModelStore {
5667 ) => void
5768}
5869
70+ const savedFreebuffModelPick = loadFreebuffModelPreference ( )
71+
5972export const useFreebuffModelStore = create < FreebuffModelStore > ( ( set ) => ( {
6073 selectedModel : resolveAvailableFreebuffModel (
61- loadFreebuffModelPreference ( ) ?? DEFAULT_FREEBUFF_MODEL_ID ,
74+ savedFreebuffModelPick ?? DEFAULT_FREEBUFF_MODEL_ID ,
6275 ) ,
6376 setSelectedModel : ( model ) =>
6477 set ( { selectedModel : getFreebuffModelDirectory ( ) . resolveSelection ( model ) } ) ,
78+ hasExplicitPick :
79+ savedFreebuffModelPick !== undefined ||
80+ loadFreebuffModelKeyPreference ( ) !== undefined ,
6581 reasoningEffortByModel : {
6682 ...loadFreebuffReasoningEfforts ( ) ,
6783 ...loadFreebuffCatalogReasoningEfforts ( ) ,
@@ -90,6 +106,27 @@ export function getSelectedFreebuffModel(): string {
90106 return useFreebuffModelStore . getState ( ) . selectedModel
91107}
92108
109+ /** The Desktop and Web slider's Balanced stop, or the catalog's
110+ * recommendation when the meter cannot start it, as on Desktop and Web. */
111+ export function freebuffDefaultModelForSession (
112+ session : FreebuffSessionResponse ,
113+ ) : string {
114+ const directory = getFreebuffModelDirectory ( )
115+ const accessTier = getFreebuffServerAccessTier ( session )
116+ const freebucks = getFreebucksInfo ( session )
117+ const balanced = getFreebuffModelPresets ( {
118+ accessTier,
119+ isSubscriber : Boolean (
120+ getSubscriptionInfo ( session ) ?. tierId ?? freebucks ?. planId ,
121+ ) ,
122+ balance : freebucks ?. balance ,
123+ } ) . find ( ( preset ) => preset . id === 'balanced' ) !
124+ const model = directory . resolveSelection ( balanced . modelId )
125+ return getFreebuffModelMeter ( { model, freebucks } ) . canStart
126+ ? model
127+ : directory . recommendedModelId ( accessTier )
128+ }
129+
93130/**
94131 * The user's effort override for a model, or null when they have none.
95132 *
@@ -133,6 +170,7 @@ function legacyEffortForCatalogKey(
133170 * key; see `saveFreebuffModelPreference`).
134171 */
135172export function persistFreebuffModelPick ( model : string ) : void {
173+ useFreebuffModelStore . setState ( { hasExplicitPick : true } )
136174 if ( getFreebuffModelDirectory ( ) . row ( model ) ?. key === model ) {
137175 saveFreebuffModelKeyPreference ( model )
138176 } else {
0 commit comments