From 4cd794c11437c7fa3d1cd03595ce4e2c5dde7672 Mon Sep 17 00:00:00 2001 From: Moltar Date: Wed, 1 Apr 2026 14:40:27 -0400 Subject: [PATCH] fix(ui): guard model formatters against non-string values --- web/src/components/CronJobList.jsx | 5 ++++- web/src/components/CronRunHistoryPanel.jsx | 5 ++++- web/src/components/SessionDetailPanel.jsx | 5 ++++- web/src/components/SessionRow.jsx | 5 ++++- web/src/pages/CronJobs.jsx | 5 ++++- web/src/pages/Log.jsx | 5 ++++- 6 files changed, 24 insertions(+), 6 deletions(-) diff --git a/web/src/components/CronJobList.jsx b/web/src/components/CronJobList.jsx index e1329f1..9eca511 100644 --- a/web/src/components/CronJobList.jsx +++ b/web/src/components/CronJobList.jsx @@ -84,7 +84,10 @@ function formatRelativeTime(timestamp) { function formatModel(model) { if (!model) return null; - const modelPart = model.includes('/') ? model.split('/').pop() : model; + const modelValue = + typeof model === 'string' ? model : model?.id || model?.model || model?.name || null; + if (!modelValue || typeof modelValue !== 'string') return null; + const modelPart = modelValue.includes('/') ? modelValue.split('/').pop() : modelValue; const lower = modelPart.toLowerCase(); if (lower.includes('kimi-k2')) return 'Kimi K2.5'; if (lower.includes('opus-4')) return 'Opus 4'; diff --git a/web/src/components/CronRunHistoryPanel.jsx b/web/src/components/CronRunHistoryPanel.jsx index 624e5bd..c94ea37 100644 --- a/web/src/components/CronRunHistoryPanel.jsx +++ b/web/src/components/CronRunHistoryPanel.jsx @@ -81,7 +81,10 @@ function formatCost(cost) { function formatModel(model) { if (!model) return null; - const part = model.includes('/') ? model.split('/').pop() : model; + const modelValue = + typeof model === 'string' ? model : model?.id || model?.model || model?.name || null; + if (!modelValue || typeof modelValue !== 'string') return null; + const part = modelValue.includes('/') ? modelValue.split('/').pop() : modelValue; const l = part.toLowerCase(); if (l.includes('kimi-k2')) return 'Kimi K2.5'; if (l.includes('opus-4')) return 'Opus 4'; diff --git a/web/src/components/SessionDetailPanel.jsx b/web/src/components/SessionDetailPanel.jsx index d2c9403..3a6f76b 100644 --- a/web/src/components/SessionDetailPanel.jsx +++ b/web/src/components/SessionDetailPanel.jsx @@ -497,7 +497,10 @@ export default function SessionDetailPanel({ isOpen, onClose, session, latestRun const formatModelName = (model) => { if (!model) return null; - const modelPart = model.includes('/') ? model.split('/').pop() : model; + const modelValue = + typeof model === 'string' ? model : model?.id || model?.model || model?.name || null; + if (!modelValue || typeof modelValue !== 'string') return null; + const modelPart = modelValue.includes('/') ? modelValue.split('/').pop() : modelValue; const lower = modelPart.toLowerCase(); if (lower.includes('kimi-k2')) return 'Kimi K2.5'; if (lower.includes('opus-4-6') || lower.includes('opus-4')) return 'Opus 4'; diff --git a/web/src/components/SessionRow.jsx b/web/src/components/SessionRow.jsx index 058942c..8bddae9 100644 --- a/web/src/components/SessionRow.jsx +++ b/web/src/components/SessionRow.jsx @@ -43,8 +43,11 @@ export default function SessionRow({ session, onClick, statusDisplay }) { const formatModelName = (model) => { if (!model) return null; + const modelValue = + typeof model === 'string' ? model : model?.id || model?.model || model?.name || null; + if (!modelValue || typeof modelValue !== 'string') return null; // Handle provider/model format (e.g., "moonshotai/kimi-k2.5") - const modelPart = model.includes('/') ? model.split('/').pop() : model; + const modelPart = modelValue.includes('/') ? modelValue.split('/').pop() : modelValue; // Simplify known model names const lower = modelPart.toLowerCase(); if (lower.includes('kimi-k2')) return 'Kimi K2.5'; diff --git a/web/src/pages/CronJobs.jsx b/web/src/pages/CronJobs.jsx index efe0aa3..1ae5926 100644 --- a/web/src/pages/CronJobs.jsx +++ b/web/src/pages/CronJobs.jsx @@ -139,7 +139,10 @@ function isWithinJustNowWindow(timestamp) { */ function formatModel(model) { if (!model) return null; - const modelPart = model.includes('/') ? model.split('/').pop() : model; + const modelValue = + typeof model === 'string' ? model : model?.id || model?.model || model?.name || null; + if (!modelValue || typeof modelValue !== 'string') return null; + const modelPart = modelValue.includes('/') ? modelValue.split('/').pop() : modelValue; const lower = modelPart.toLowerCase(); if (lower.includes('kimi-k2')) return 'Kimi K2.5'; if (lower.includes('opus-4')) return 'Opus 4'; diff --git a/web/src/pages/Log.jsx b/web/src/pages/Log.jsx index b93e8d7..531b626 100644 --- a/web/src/pages/Log.jsx +++ b/web/src/pages/Log.jsx @@ -197,7 +197,10 @@ const groupByDay = (logs) => { function formatModel(model) { if (!model) return null; - const modelPart = model.includes('/') ? model.split('/').pop() : model; + const modelValue = + typeof model === 'string' ? model : model?.id || model?.model || model?.name || null; + if (!modelValue || typeof modelValue !== 'string') return null; + const modelPart = modelValue.includes('/') ? modelValue.split('/').pop() : modelValue; const lower = modelPart.toLowerCase(); if (lower.includes('kimi-k2')) return 'Kimi K2.5'; if (lower.includes('opus-4')) return 'Opus 4';