diff --git a/frontend/src/api/admin/ops.ts b/frontend/src/api/admin/ops.ts index 64f6a6d0..0541bb59 100644 --- a/frontend/src/api/admin/ops.ts +++ b/frontend/src/api/admin/ops.ts @@ -969,6 +969,10 @@ export interface OpsErrorLog { client_ip?: string | null request_path?: string stream?: boolean + + // Model mapping context for ops error observability + requested_model?: string + upstream_model?: string } export interface OpsErrorDetail extends OpsErrorLog { diff --git a/frontend/src/views/admin/ops/components/OpsErrorDetailModal.vue b/frontend/src/views/admin/ops/components/OpsErrorDetailModal.vue index a7edff96..0817f239 100644 --- a/frontend/src/views/admin/ops/components/OpsErrorDetailModal.vue +++ b/frontend/src/views/admin/ops/components/OpsErrorDetailModal.vue @@ -59,7 +59,14 @@
{{ t('admin.ops.errorDetail.model') }}
- {{ detail.model || '—' }} + +
@@ -213,6 +220,22 @@ function isUpstreamError(d: OpsErrorDetail | null): boolean { return phase === 'upstream' && owner === 'provider' } +function hasModelMapping(d: OpsErrorDetail | null): boolean { + if (!d) return false + const requested = String(d.requested_model || '').trim() + const upstream = String(d.upstream_model || '').trim() + return !!requested && !!upstream && requested !== upstream +} + +function displayModel(d: OpsErrorDetail | null): string { + if (!d) return '' + const upstream = String(d.upstream_model || '').trim() + if (upstream) return upstream + const requested = String(d.requested_model || '').trim() + if (requested) return requested + return String(d.model || '').trim() +} + const correlatedUpstream = ref([]) const correlatedUpstreamLoading = ref(false) diff --git a/frontend/src/views/admin/ops/components/OpsErrorLogTable.vue b/frontend/src/views/admin/ops/components/OpsErrorLogTable.vue index 28868552..58846db6 100644 --- a/frontend/src/views/admin/ops/components/OpsErrorLogTable.vue +++ b/frontend/src/views/admin/ops/components/OpsErrorLogTable.vue @@ -83,11 +83,22 @@ -
- - {{ log.model }} - - - +
+ +
@@ -193,6 +204,28 @@ function isUpstreamRow(log: OpsErrorLog): boolean { return phase === 'upstream' && owner === 'provider' } +function hasModelMapping(log: OpsErrorLog): boolean { + const requested = String(log.requested_model || '').trim() + const upstream = String(log.upstream_model || '').trim() + return !!requested && !!upstream && requested !== upstream +} + +function modelMappingTooltip(log: OpsErrorLog): string { + const requested = String(log.requested_model || '').trim() + const upstream = String(log.upstream_model || '').trim() + if (!requested && !upstream) return '' + if (requested && upstream) return `${requested} → ${upstream}` + return upstream || requested +} + +function displayModel(log: OpsErrorLog): string { + const upstream = String(log.upstream_model || '').trim() + if (upstream) return upstream + const requested = String(log.requested_model || '').trim() + if (requested) return requested + return String(log.model || '').trim() +} + function getTypeBadge(log: OpsErrorLog): { label: string; className: string } { const phase = String(log.phase || '').toLowerCase() const owner = String(log.error_owner || '').toLowerCase() @@ -263,4 +296,4 @@ function formatSmartMessage(msg: string): string { return msg.length > 200 ? msg.substring(0, 200) + '...' : msg } - \ No newline at end of file +