@gotcos/glasses-server 6.2.1 → 6.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,42 +1,159 @@
1
- export type ClaudeModelPreference = 'opus' | 'sonnet' | 'haiku'
2
- export type CodexModelPreference = 'codex-high'
1
+ export type ClaudeModelPreference = 'opus' | 'fable' | 'sonnet' | 'haiku'
2
+
3
+ // Stable app-level slots. Concrete GPT model ids resolve at runtime from the
4
+ // local Codex CLI catalog, so a shipped glasses app keeps tracking new releases.
5
+ export type CodexModelPreference = 'codex-frontier' | 'codex-balanced'
3
6
  export type ModelPreference = ClaudeModelPreference | CodexModelPreference
4
7
 
8
+ // Preserve the public server's established fast, broadly available default.
5
9
  export const DEFAULT_MODEL = 'sonnet' as const
6
- export const CODEX_HIGH_MODEL: CodexModelPreference = 'codex-high'
10
+ export const CODEX_FRONTIER_MODEL: CodexModelPreference = 'codex-frontier'
11
+ export const CODEX_BALANCED_MODEL: CodexModelPreference = 'codex-balanced'
12
+ // Backward-compatible export for callers that predate the two-slot catalog.
13
+ export const CODEX_HIGH_MODEL: CodexModelPreference = CODEX_FRONTIER_MODEL
14
+ // Existing 6.1–6.3 installs may pin the legacy codex-high slot. Frontier is its
15
+ // migration target; Balanced remains auto-catalog even when this override is set.
16
+ export const CODEX_MODEL_ID = process.env.COS_CODEX_MODEL?.trim() ?? ''
17
+
18
+ export type CodexReasoningEffort = 'low' | 'medium' | 'high' | 'xhigh' | 'max' | 'ultra'
19
+ const CODEX_REASONING_EFFORT_SET = new Set<CodexReasoningEffort>(['low', 'medium', 'high', 'xhigh', 'max', 'ultra'])
20
+
21
+ export function resolveConfiguredCodexReasoningEffort(): CodexReasoningEffort {
22
+ const raw = process.env.COS_CODEX_REASONING_EFFORT?.trim().toLowerCase()
23
+ return raw && CODEX_REASONING_EFFORT_SET.has(raw as CodexReasoningEffort)
24
+ ? raw as CodexReasoningEffort
25
+ : 'high'
26
+ }
27
+
28
+ export const CODEX_HIGH_REASONING_EFFORT: CodexReasoningEffort = resolveConfiguredCodexReasoningEffort()
29
+
30
+ export const MODEL_OPTIONS: ModelPreference[] = [
31
+ 'opus',
32
+ 'fable',
33
+ 'sonnet',
34
+ CODEX_FRONTIER_MODEL,
35
+ CODEX_BALANCED_MODEL,
36
+ ]
37
+
38
+ const MODEL_SET = new Set<ModelPreference>([
39
+ 'opus',
40
+ 'fable',
41
+ 'sonnet',
42
+ 'haiku',
43
+ CODEX_FRONTIER_MODEL,
44
+ CODEX_BALANCED_MODEL,
45
+ ])
46
+
47
+ // Bare Claude tier aliases resolve to the newest model in that tier at spawn.
48
+ // The [1m] suffix keeps the large-context contract without pinning a version.
49
+ export const CLAUDE_CLI_MODEL_ID: Record<ClaudeModelPreference, string> = {
50
+ opus: 'opus[1m]',
51
+ fable: 'fable[1m]',
52
+ sonnet: 'sonnet[1m]',
53
+ haiku: 'haiku',
54
+ }
55
+
56
+ export function resolveClaudeCliModelId(model: ClaudeModelPreference): string {
57
+ return CLAUDE_CLI_MODEL_ID[model] ?? CLAUDE_CLI_MODEL_ID[DEFAULT_MODEL]
58
+ }
59
+
60
+ /** Format a concrete Claude CLI model id for diagnostics. */
61
+ export function formatResolvedModelDisplay(cliModelId: string | undefined): string {
62
+ if (!cliModelId) return ''
63
+ const oneM = cliModelId.includes('[1m]')
64
+ const bare = cliModelId.replace('[1m]', '')
65
+ const match = /^claude-([a-z]+)-(\d+(?:-\d+)*)$/.exec(bare)
66
+ if (!match) return cliModelId
67
+ const family = match[1].charAt(0).toUpperCase() + match[1].slice(1)
68
+ const version = match[2].split('-').join('.')
69
+ return `${family} ${version}${oneM ? ' (1M)' : ''}`
70
+ }
71
+
72
+ export type EffortPreference = 'high' | 'xhigh' | 'max' | 'ultracode'
73
+ export const DEFAULT_EFFORT: EffortPreference = 'high'
74
+ export const EFFORT_OPTIONS: EffortPreference[] = ['high', 'xhigh', 'max', 'ultracode']
75
+ const EFFORT_SET = new Set<EffortPreference>(EFFORT_OPTIONS)
76
+ export const ULTRACODE_KEYWORD = 'ultracode'
77
+
78
+ export function isEffortPreference(value: unknown): value is EffortPreference {
79
+ return typeof value === 'string' && EFFORT_SET.has(value as EffortPreference)
80
+ }
7
81
 
8
- // Optional codex model passed to `codex exec --model`. Empty (the default) means
9
- // "use whatever model your codex CLI is configured for" — so the public server
10
- // never pins a specific (possibly unreleased) model id. Set COS_CODEX_MODEL to
11
- // pin one. COS_CODEX_REASONING_EFFORT tunes the reasoning level (default high).
12
- export const CODEX_MODEL_ID = process.env.COS_CODEX_MODEL ?? ''
13
- export const CODEX_HIGH_REASONING_EFFORT = process.env.COS_CODEX_REASONING_EFFORT ?? 'high'
82
+ export function normalizeEffortPreference(value: unknown): EffortPreference | undefined {
83
+ return isEffortPreference(value) ? value : undefined
84
+ }
85
+
86
+ /** Map the UI-only ultracode choice to a Claude CLI effort flag. */
87
+ export function resolveCliEffortFlag(effort: EffortPreference): 'high' | 'xhigh' | 'max' {
88
+ return effort === 'ultracode' ? 'xhigh' : effort
89
+ }
90
+
91
+ // Codex Fast mode is emitted only when the selected live model advertises it.
92
+ export const CODEX_SERVICE_TIER = 'priority'
14
93
 
15
- export const MODEL_OPTIONS: ModelPreference[] = ['opus', 'sonnet', 'haiku', 'codex-high']
94
+ export function resolveCodexReasoningEffort(effort: EffortPreference | undefined): CodexReasoningEffort {
95
+ if (effort === 'ultracode') return 'ultra'
96
+ if (effort === 'max') return 'max'
97
+ if (effort === 'xhigh') return 'xhigh'
98
+ return 'high'
99
+ }
16
100
 
17
- const MODEL_SET = new Set<ModelPreference>(['opus', 'sonnet', 'haiku', 'codex-high'])
101
+ export function effortLabel(effort: EffortPreference): string {
102
+ switch (effort) {
103
+ case 'xhigh': return 'Extra High'
104
+ case 'max': return 'Max'
105
+ case 'ultracode': return 'Ultracode'
106
+ case 'high':
107
+ default:
108
+ return 'High'
109
+ }
110
+ }
18
111
 
19
112
  export function isModelPreference(value: unknown): value is ModelPreference {
20
113
  return typeof value === 'string' && MODEL_SET.has(value as ModelPreference)
21
114
  }
22
115
 
23
116
  export function normalizeModelPreference(value: unknown): ModelPreference | undefined {
117
+ // Existing installs persist codex-high. Migrate it to the live frontier slot.
118
+ if (value === 'codex-high') return CODEX_FRONTIER_MODEL
24
119
  return isModelPreference(value) ? value : undefined
25
120
  }
26
121
 
27
122
  export function isClaudeModel(model: ModelPreference): model is ClaudeModelPreference {
28
- return model === 'opus' || model === 'sonnet' || model === 'haiku'
123
+ return model === 'opus' || model === 'fable' || model === 'sonnet' || model === 'haiku'
29
124
  }
30
125
 
31
126
  export function isCodexModel(model: ModelPreference): model is CodexModelPreference {
32
- return model === 'codex-high'
127
+ return model === CODEX_FRONTIER_MODEL || model === CODEX_BALANCED_MODEL
128
+ }
129
+
130
+ export interface RuntimeCodexModelLabel {
131
+ preference: CodexModelPreference
132
+ displayName: string
133
+ }
134
+
135
+ const runtimeCodexLabels: Partial<Record<CodexModelPreference, string>> = {}
136
+
137
+ export function setRuntimeCodexModelLabels(options: RuntimeCodexModelLabel[]): void {
138
+ for (const option of options) {
139
+ if (!isCodexModel(option.preference)) continue
140
+ const label = typeof option.displayName === 'string' ? option.displayName.trim() : ''
141
+ if (label) runtimeCodexLabels[option.preference] = label
142
+ }
143
+ }
144
+
145
+ export function resetRuntimeCodexModelLabels(): void {
146
+ delete runtimeCodexLabels[CODEX_FRONTIER_MODEL]
147
+ delete runtimeCodexLabels[CODEX_BALANCED_MODEL]
33
148
  }
34
149
 
35
150
  export function modelLabel(model: ModelPreference): string {
36
151
  switch (model) {
152
+ case 'fable': return 'Fable'
37
153
  case 'sonnet': return 'Sonnet'
38
154
  case 'haiku': return 'Haiku'
39
- case 'codex-high': return 'Codex High'
155
+ case 'codex-frontier': return runtimeCodexLabels[model] ?? 'GPT Frontier'
156
+ case 'codex-balanced': return runtimeCodexLabels[model] ?? 'GPT Balanced'
40
157
  case 'opus':
41
158
  default:
42
159
  return 'Opus'
@@ -45,9 +162,11 @@ export function modelLabel(model: ModelPreference): string {
45
162
 
46
163
  export function modelShortLabel(model: ModelPreference): string {
47
164
  switch (model) {
165
+ case 'fable': return 'Fable'
48
166
  case 'sonnet': return 'Sonnet'
49
167
  case 'haiku': return 'Haiku'
50
- case 'codex-high': return 'Codex H'
168
+ case 'codex-frontier': return 'GPT Max'
169
+ case 'codex-balanced': return 'GPT Bal'
51
170
  case 'opus':
52
171
  default:
53
172
  return 'Opus'
@@ -56,9 +175,11 @@ export function modelShortLabel(model: ModelPreference): string {
56
175
 
57
176
  export function modelButtonLabel(model: ModelPreference): string {
58
177
  switch (model) {
178
+ case 'fable': return 'FABLE'
59
179
  case 'sonnet': return 'SNNT'
60
180
  case 'haiku': return 'HAIKU'
61
- case 'codex-high': return 'CODEX H'
181
+ case 'codex-frontier': return 'GPT MAX'
182
+ case 'codex-balanced': return 'GPT BAL'
62
183
  case 'opus':
63
184
  default:
64
185
  return 'OPUS'
@@ -67,9 +188,11 @@ export function modelButtonLabel(model: ModelPreference): string {
67
188
 
68
189
  export function modelTag(model: ModelPreference): string {
69
190
  switch (model) {
191
+ case 'fable': return 'F'
70
192
  case 'sonnet': return 'S'
71
193
  case 'haiku': return 'H'
72
- case 'codex-high': return 'CH'
194
+ case 'codex-frontier': return 'GF'
195
+ case 'codex-balanced': return 'GB'
73
196
  case 'opus':
74
197
  default:
75
198
  return 'O'