From bd8eadb75b92601e4aabe4353b0abd9600af7836 Mon Sep 17 00:00:00 2001
From: Ethan0x0000 <3352979663@qq.com>
Date: Sun, 22 Mar 2026 19:56:29 +0800
Subject: [PATCH 1/2] feat(ops): enhance error observability with additional
context fields and UI updates
---
frontend/src/api/admin/ops.ts | 7 ++
frontend/src/i18n/locales/en.ts | 17 ++++-
frontend/src/i18n/locales/zh.ts | 17 ++++-
.../ops/components/OpsErrorDetailModal.vue | 39 ++++++++++-
.../admin/ops/components/OpsErrorLogTable.vue | 64 +++++++++++++++++--
5 files changed, 135 insertions(+), 9 deletions(-)
diff --git a/frontend/src/api/admin/ops.ts b/frontend/src/api/admin/ops.ts
index 64f6a6d0..ac58eff4 100644
--- a/frontend/src/api/admin/ops.ts
+++ b/frontend/src/api/admin/ops.ts
@@ -969,6 +969,13 @@ export interface OpsErrorLog {
client_ip?: string | null
request_path?: string
stream?: boolean
+
+ // Error observability context (endpoint + model mapping)
+ inbound_endpoint?: string
+ upstream_endpoint?: string
+ requested_model?: string
+ upstream_model?: string
+ request_type?: number | null
}
export interface OpsErrorDetail extends OpsErrorLog {
diff --git a/frontend/src/i18n/locales/en.ts b/frontend/src/i18n/locales/en.ts
index e5a370c8..b5bba9a2 100644
--- a/frontend/src/i18n/locales/en.ts
+++ b/frontend/src/i18n/locales/en.ts
@@ -3486,7 +3486,12 @@ export default {
typeRequest: 'Request',
typeAuth: 'Auth',
typeRouting: 'Routing',
- typeInternal: 'Internal'
+ typeInternal: 'Internal',
+ endpoint: 'Endpoint',
+ requestType: 'Type',
+ requestTypeSync: 'Sync',
+ requestTypeStream: 'Stream',
+ requestTypeWs: 'WS'
},
// Error Details Modal
errorDetails: {
@@ -3572,6 +3577,16 @@ export default {
latency: 'Request Duration',
businessLimited: 'Business Limited',
requestPath: 'Request Path',
+ inboundEndpoint: 'Inbound Endpoint',
+ upstreamEndpoint: 'Upstream Endpoint',
+ requestedModel: 'Requested Model',
+ upstreamModel: 'Upstream Model',
+ requestType: 'Request Type',
+ requestTypeUnknown: 'Unknown',
+ requestTypeSync: 'Sync',
+ requestTypeStream: 'Stream',
+ requestTypeWs: 'WebSocket',
+ modelMapping: 'Model Mapping',
timings: 'Timings',
auth: 'Auth',
routing: 'Routing',
diff --git a/frontend/src/i18n/locales/zh.ts b/frontend/src/i18n/locales/zh.ts
index ac6632be..05c69426 100644
--- a/frontend/src/i18n/locales/zh.ts
+++ b/frontend/src/i18n/locales/zh.ts
@@ -3651,7 +3651,12 @@ export default {
typeRequest: '请求',
typeAuth: '认证',
typeRouting: '路由',
- typeInternal: '内部'
+ typeInternal: '内部',
+ endpoint: '端点',
+ requestType: '类型',
+ requestTypeSync: '同步',
+ requestTypeStream: '流式',
+ requestTypeWs: 'WS'
},
// Error Details Modal
errorDetails: {
@@ -3737,6 +3742,16 @@ export default {
latency: '请求时长',
businessLimited: '业务限制',
requestPath: '请求路径',
+ inboundEndpoint: '入站端点',
+ upstreamEndpoint: '上游端点',
+ requestedModel: '请求模型',
+ upstreamModel: '上游模型',
+ requestType: '请求类型',
+ requestTypeUnknown: '未知',
+ requestTypeSync: '同步',
+ requestTypeStream: '流式',
+ requestTypeWs: 'WebSocket',
+ modelMapping: '模型映射',
timings: '时序信息',
auth: '认证',
routing: '路由',
diff --git a/frontend/src/views/admin/ops/components/OpsErrorDetailModal.vue b/frontend/src/views/admin/ops/components/OpsErrorDetailModal.vue
index a7edff96..4bcd0c41 100644
--- a/frontend/src/views/admin/ops/components/OpsErrorDetailModal.vue
+++ b/frontend/src/views/admin/ops/components/OpsErrorDetailModal.vue
@@ -59,7 +59,28 @@
{{ t('admin.ops.errorDetail.model') }}
- {{ detail.model || '—' }}
+
+ {{ detail.requested_model }}
+ →
+ {{ detail.upstream_model }}
+
+
+ {{ detail.requested_model || detail.model || '—' }}
+
+
+
+
+
+
{{ t('admin.ops.errorDetail.inboundEndpoint') }}
+
+ {{ detail.inbound_endpoint || '—' }}
+
+
+
+
+
{{ t('admin.ops.errorDetail.upstreamEndpoint') }}
+
+ {{ detail.upstream_endpoint || '—' }}
@@ -72,6 +93,13 @@
+
+
{{ t('admin.ops.errorDetail.requestType') }}
+
+ {{ formatRequestTypeLabel(detail.request_type) }}
+
+
+
{{ t('admin.ops.errorDetail.message') }}
@@ -213,6 +241,15 @@ function isUpstreamError(d: OpsErrorDetail | null): boolean {
return phase === 'upstream' && owner === 'provider'
}
+function formatRequestTypeLabel(type: number | null | undefined): string {
+ switch (type) {
+ case 1: return t('admin.ops.errorDetail.requestTypeSync')
+ case 2: return t('admin.ops.errorDetail.requestTypeStream')
+ case 3: return t('admin.ops.errorDetail.requestTypeWs')
+ default: return t('admin.ops.errorDetail.requestTypeUnknown')
+ }
+}
+
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..23377257 100644
--- a/frontend/src/views/admin/ops/components/OpsErrorLogTable.vue
+++ b/frontend/src/views/admin/ops/components/OpsErrorLogTable.vue
@@ -17,6 +17,9 @@
{{ t('admin.ops.errorLog.type') }}
|
+
+ {{ t('admin.ops.errorLog.endpoint') }}
+ |
{{ t('admin.ops.errorLog.platform') }}
|
@@ -42,7 +45,7 @@
- |
+ |
{{ t('admin.ops.errorLog.noErrors') }}
|
@@ -74,6 +77,18 @@
+
+
+
+
+
+ {{ log.inbound_endpoint }}
+
+
+ -
+
+ |
+
@@ -83,11 +98,22 @@
|
-
-
- {{ log.model }}
-
- -
+
+
+
+
+ {{ log.requested_model }}
+ →
+ {{ log.upstream_model }}
+
+
+
+
+
+ {{ displayModel(log) }}
+
+ -
+
|
@@ -138,6 +164,12 @@
>
{{ log.severity }}
+
+ {{ formatRequestType(log.request_type) }}
+
@@ -193,6 +225,26 @@ function isUpstreamRow(log: OpsErrorLog): boolean {
return phase === 'upstream' && owner === 'provider'
}
+function formatEndpointTooltip(log: OpsErrorLog): string {
+ const parts: string[] = []
+ if (log.inbound_endpoint) parts.push(`Inbound: ${log.inbound_endpoint}`)
+ if (log.upstream_endpoint) parts.push(`Upstream: ${log.upstream_endpoint}`)
+ return parts.join('\n') || ''
+}
+
+function displayModel(log: OpsErrorLog): string {
+ return log.requested_model || log.model || ''
+}
+
+function formatRequestType(type: number | null | undefined): string {
+ switch (type) {
+ case 1: return t('admin.ops.errorLog.requestTypeSync')
+ case 2: return t('admin.ops.errorLog.requestTypeStream')
+ case 3: return t('admin.ops.errorLog.requestTypeWs')
+ default: return ''
+ }
+}
+
function getTypeBadge(log: OpsErrorLog): { label: string; className: string } {
const phase = String(log.phase || '').toLowerCase()
const owner = String(log.error_owner || '').toLowerCase()
From ecad083ffc414e197cf9cf3490f194c0eff32c7f Mon Sep 17 00:00:00 2001
From: Ethan0x0000 <3352979663@qq.com>
Date: Mon, 23 Mar 2026 15:50:12 +0800
Subject: [PATCH 2/2] fix(ops): prefer upstream_model in ops error displays
---
.../ops/components/OpsErrorDetailModal.vue | 20 ++++++++++++--
.../admin/ops/components/OpsErrorLogTable.vue | 26 ++++++++++++++++---
2 files changed, 40 insertions(+), 6 deletions(-)
diff --git a/frontend/src/views/admin/ops/components/OpsErrorDetailModal.vue b/frontend/src/views/admin/ops/components/OpsErrorDetailModal.vue
index 4bcd0c41..d29607e5 100644
--- a/frontend/src/views/admin/ops/components/OpsErrorDetailModal.vue
+++ b/frontend/src/views/admin/ops/components/OpsErrorDetailModal.vue
@@ -59,13 +59,13 @@
{{ t('admin.ops.errorDetail.model') }}
-
+
{{ detail.requested_model }}
→
{{ detail.upstream_model }}
- {{ detail.requested_model || detail.model || '—' }}
+ {{ displayModel(detail) || '—' }}
@@ -250,6 +250,22 @@ function formatRequestTypeLabel(type: number | null | undefined): string {
}
}
+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 23377257..2b3825a2 100644
--- a/frontend/src/views/admin/ops/components/OpsErrorLogTable.vue
+++ b/frontend/src/views/admin/ops/components/OpsErrorLogTable.vue
@@ -99,8 +99,8 @@
-
-
+
+
{{ log.requested_model }}
→
@@ -232,8 +232,26 @@ function formatEndpointTooltip(log: OpsErrorLog): string {
return parts.join('\n') || ''
}
+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 {
- return log.requested_model || log.model || ''
+ 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 formatRequestType(type: number | null | undefined): string {
@@ -315,4 +333,4 @@ function formatSmartMessage(msg: string): string {
return msg.length > 200 ? msg.substring(0, 200) + '...' : msg
}
-
\ No newline at end of file
+
|