File size: 1,722 Bytes
5f40163
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
import { create } from "zustand";
import type { FreeModelSet } from "#/utils/format-model-name";

interface FreeModelsState {
  /**
   * DB-driven set of free ``provider/model`` ids (the same channel that carries
   * `verified`). Empty on backends without free metadata (e.g. the local
   * agent-server), so consumers uniformly treat "not in set" as paid.
   */
  freeModels: FreeModelSet;
  /** DB-driven default OpenHands model id (``openhands/<model>``), or null. */
  defaultModel: string | null;
  /** True once the backend flags query has settled at least once. */
  defaultModelReady: boolean;
}

interface FreeModelsActions {
  /**
   * Replaces the DB-driven flags. Called once by the app-level hydrator
   * ({@link useHydrateFreeModels}) after the backend model list is fetched, so
   * leaf components can read the flags synchronously via zustand selectors
   * without needing a QueryClientProvider in scope.
   */
  setFlags: (flags: {
    freeModels: FreeModelSet;
    defaultModel: string | null;
  }) => void;
  markDefaultModelReady: () => void;
  resetFlags: () => void;
}

type FreeModelsStore = FreeModelsState & FreeModelsActions;

const EMPTY_FREE_MODELS: FreeModelSet = new Set<string>();

export const useFreeModelsStore = create<FreeModelsStore>()((set) => ({
  freeModels: EMPTY_FREE_MODELS,
  defaultModel: null,
  defaultModelReady: false,
  setFlags: (flags) =>
    set({
      freeModels: flags.freeModels,
      defaultModel: flags.defaultModel,
      defaultModelReady: true,
    }),
  markDefaultModelReady: () => set({ defaultModelReady: true }),
  resetFlags: () =>
    set({
      freeModels: EMPTY_FREE_MODELS,
      defaultModel: null,
      defaultModelReady: false,
    }),
}));