free-coding-models 0.5.27 → 0.5.28

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.
@@ -48,8 +48,8 @@
48
48
  <link rel="preconnect" href="https://fonts.googleapis.com">
49
49
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
50
50
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
51
- <script type="module" crossorigin src="/assets/index-JUPDB-J-.js"></script>
52
- <link rel="stylesheet" crossorigin href="/assets/index-avN2GM3H.css">
51
+ <script type="module" crossorigin src="/assets/index-Pr3waI0-.js"></script>
52
+ <link rel="stylesheet" crossorigin href="/assets/index-BRFowJv5.css">
53
53
  </head>
54
54
  <body>
55
55
  <div id="root"></div>
package/web/server.js CHANGED
@@ -264,6 +264,10 @@ function serializeModel(result) {
264
264
  const jitter = getJitter(result)
265
265
  const stability = getStabilityScore(result)
266
266
  const latest = result.pings.length > 0 ? result.pings[result.pings.length - 1] : null
267
+ const routerConfig = config.router || {}
268
+ const activeSetName = routerConfig.activeSet || 'fast-coding'
269
+ const activeSetModels = routerConfig.sets?.[activeSetName]?.models || []
270
+ const inRouterSet = activeSetModels.some((m) => m.provider === result.providerKey && m.model === result.modelId)
267
271
 
268
272
  return {
269
273
  idx: result.idx,
@@ -290,6 +294,7 @@ function serializeModel(result) {
290
294
  pingHistory: result.pings.slice(-20).map((p) => ({ ms: p.ms, code: p.code })),
291
295
  pingCount: result.pings.length,
292
296
  hasApiKey: !!getApiKey(config, result.providerKey),
297
+ inRouterSet,
293
298
  benchmarkKey: key,
294
299
  isBenchmarking: benchmarkRunning.has(key),
295
300
  benchmark: benchmarkResults.get(key) || null,
@@ -23,6 +23,7 @@ import {
23
23
  IconChecks,
24
24
  IconHourglass,
25
25
  IconHourglassOff,
26
+ IconCircleDotted,
26
27
  IconLock,
27
28
  IconFlame,
28
29
  IconError404,
@@ -69,10 +70,10 @@ const ERROR_ICON = {
69
70
  '504': { Icon: IconClock, color: HEALTH_ICON_COLOR.danger },
70
71
  }
71
72
 
72
- function statusLabel(status, httpCode) {
73
+ function statusLabel(status, httpCode, inRouterSet) {
73
74
  if (status === 'noauth') return 'NO KEY'
74
75
  if (status === 'auth_error') return 'AUTH FAIL'
75
- if (status === 'pending') return 'wait'
76
+ if (status === 'pending') return inRouterSet ? 'wait' : 'NOT IN SET'
76
77
  if (status === 'timeout') return 'TIMEOUT'
77
78
  if (status === 'down') {
78
79
  return ERROR_LABELS[httpCode] || (httpCode || 'ERROR')
@@ -81,20 +82,21 @@ function statusLabel(status, httpCode) {
81
82
  return '?'
82
83
  }
83
84
 
84
- function statusClass(status) {
85
+ function statusClass(status, inRouterSet) {
85
86
  if (status === 'noauth') return styles.noKey
86
87
  if (status === 'up') return styles.up
87
88
  if (status === 'down') return styles.error
88
89
  if (status === 'timeout') return styles.warning
89
90
  if (status === 'auth_error') return styles.errorBold
90
- if (status === 'pending') return styles.warning
91
+ if (status === 'pending') return inRouterSet ? styles.warning : styles.notInSet
91
92
  return styles.dim
92
93
  }
93
94
 
94
- export default function HealthCell({ status, httpCode }) {
95
- const text = statusLabel(status, httpCode)
96
- const cls = statusClass(status)
95
+ export default function HealthCell({ status, httpCode, inRouterSet = true }) {
96
+ const text = statusLabel(status, httpCode, inRouterSet)
97
+ const cls = statusClass(status, inRouterSet)
97
98
  const isNoKey = status === 'noauth'
99
+ const isNotInSet = status === 'pending' && !inRouterSet
98
100
 
99
101
  // 📖 Pick the right icon + color combo for this state.
100
102
  let Icon = null
@@ -105,6 +107,9 @@ export default function HealthCell({ status, httpCode }) {
105
107
  } else if (status === 'timeout') {
106
108
  Icon = IconHourglassOff
107
109
  iconColor = HEALTH_ICON_COLOR.warning
110
+ } else if (isNotInSet) {
111
+ Icon = IconCircleDotted
112
+ iconColor = HEALTH_ICON_COLOR.dim
108
113
  } else if (status === 'pending') {
109
114
  Icon = IconHourglass
110
115
  iconColor = HEALTH_ICON_COLOR.warning
@@ -21,6 +21,9 @@
21
21
  .error { color: #ff4444; }
22
22
  .errorBold { color: #ff4444; font-weight: 800; }
23
23
  .dim { color: var(--color-text-dim); }
24
+ /* 📖 Models not in the active router set — muted text so they stand out from
25
+ 📖 genuinely 'pending' models that are still waiting for their first probe. */
26
+ .notInSet { color: #4a4a5a; opacity: 0.7; }
24
27
 
25
28
  /* 📖 The "NO KEY" treatment is intentionally louder than the other states:
26
29
  📖 - yellow chip background instead of plain text
@@ -54,3 +57,4 @@
54
57
  :global([data-theme="light"]) .error,
55
58
  :global([data-theme="light"]) .errorBold { color: #c02323; }
56
59
  :global([data-theme="light"]) .dim { color: #888; }
60
+ :global([data-theme="light"]) .notInSet { color: #a0a0a8; }
@@ -1,10 +1,13 @@
1
1
  /**
2
2
  * @file web/src/components/atoms/StatusDot.jsx
3
3
  * @description Renders a colored status indicator dot (green=up, red=down, gray=pending).
4
+ * 📖 When a model is not in the active router set and still pending, we show
5
+ * 📖 a muted gray dot instead of the animated yellow — this makes it visually
6
+ * 📖 clear that the model is *not being tested* rather than *still loading*.
4
7
  */
5
8
  import styles from './StatusDot.module.css'
6
9
 
7
- export default function StatusDot({ status }) {
8
- const cls = status === 'up' ? styles.up : status === 'timeout' ? styles.timeout : status === 'down' ? styles.down : styles.pending
10
+ export default function StatusDot({ status, inRouterSet = true }) {
11
+ const cls = status === 'up' ? styles.up : status === 'timeout' ? styles.timeout : status === 'down' ? styles.down : (status === 'pending' && !inRouterSet) ? styles.notInSet : styles.pending
9
12
  return <span className={`${styles.dot} ${cls}`} />
10
13
  }
@@ -6,10 +6,14 @@
6
6
  margin-right: 6px;
7
7
  vertical-align: middle;
8
8
  }
9
- .up { background: #00ff88; box-shadow: 0 0 6px rgba(0,255,136,0.4); }
10
- .down { background: #ff4444; }
11
- .timeout { background: #ff4444; }
12
- .pending { background: #555570; animation: pulse 1.5s ease-in-out infinite; }
9
+ .up { background: #00ff88; box-shadow: 0 0 6px rgba(0,255,136,0.4); }
10
+ .down { background: #ff4444; }
11
+ .timeout { background: #ff4444; }
12
+ .pending { background: #555570; animation: pulse 1.5s ease-in-out infinite; }
13
+ /* 📖 Models not in the active router set — static dim dot, no pulse animation.
14
+ 📖 Visually distinct from 'pending' (yellow animated) so users know this
15
+ 📖 model is simply not being tested, not still loading. */
16
+ .notInSet { background: #3a3a4a; opacity: 0.5; }
13
17
 
14
18
  @keyframes pulse {
15
19
  0%, 100% { box-shadow: 0 0 0 0 rgba(118,185,0,0.25); }
@@ -18,7 +22,8 @@
18
22
 
19
23
  /* 📖 Light theme: deep green/red for the dot so it still reads as "up"/"down"
20
24
  📖 on a white card; the glow halo is dimmed so it doesn't blow out. */
21
- :global([data-theme="light"]) .up { background: #008f4d; box-shadow: 0 0 4px rgba(0,143,77,0.35); }
25
+ :global([data-theme="light"]) .up { background: #008f4d; box-shadow: 0 0 4px rgba(0,143,77,0.35); }
22
26
  :global([data-theme="light"]) .down,
23
- :global([data-theme="light"]) .timeout { background: #c8143a; }
24
- :global([data-theme="light"]) .pending { background: #888899; }
27
+ :global([data-theme="light"]) .timeout { background: #c8143a; }
28
+ :global([data-theme="light"]) .pending { background: #888899; }
29
+ :global([data-theme="light"]) .notInSet { background: #b0b0b8; opacity: 0.6; }
@@ -67,7 +67,7 @@ function ModelCellRenderer({ row }) {
67
67
  const showNoKey = !m.hasApiKey && !m.cliOnly
68
68
  return (
69
69
  <div className={styles.modelCell}>
70
- <StatusDot status={m.status} />
70
+ <StatusDot status={m.status} inRouterSet={m.inRouterSet} />
71
71
  <div className={styles.modelMeta}>
72
72
  <div className={styles.modelHeader}>
73
73
  <span className={styles.modelName}>{m.label}</span>
@@ -120,7 +120,7 @@ function AvgPingCellRenderer({ row }) {
120
120
 
121
121
  function HealthCellRenderer({ row }) {
122
122
  const m = row.original
123
- return <HealthCell status={m.status} httpCode={m.httpCode} />
123
+ return <HealthCell status={m.status} httpCode={m.httpCode} inRouterSet={m.inRouterSet} />
124
124
  }
125
125
 
126
126
  function VerdictCellRenderer({ row }) {
@@ -526,6 +526,9 @@ export default function ModelTable({
526
526
  if (m.status === 'noauth' || m.status === 'auth_error') {
527
527
  rowClasses.push(styles.unusable)
528
528
  }
529
+ if (m.status === 'pending' && m.inRouterSet === false) {
530
+ rowClasses.push(styles.notInSetRow)
531
+ }
529
532
  return (
530
533
  <Fragment key={row.id}>
531
534
  <tr
@@ -345,6 +345,15 @@
345
345
  opacity: 0.8;
346
346
  }
347
347
 
348
+ /* 📖 Models not in the active router set — slightly faded so users can
349
+ 📖 instantly see which models are being tested vs just cataloged. */
350
+ .notInSetRow {
351
+ opacity: 0.6;
352
+ }
353
+ .notInSetRow:hover {
354
+ opacity: 0.85;
355
+ }
356
+
348
357
  /* ─── M3: per-row endpoint install plug ─── */
349
358
  .launchCell {
350
359
  display: flex;