mirror of
https://github.com/Wei-Shaw/sub2api.git
synced 2026-10-30 16:23:31 +00:00
feat(usage): 使用记录展示映射前的推理强度
用量行新增 requested_reasoning_effort,记录分组策略与模型族改写前的客户端请求值;推理强度列与模型列一致,主行显示请求值,有映射时用 ↳ 展示实际转发值。
This commit is contained in:
@@ -91,8 +91,16 @@
|
||||
</template>
|
||||
|
||||
<template #cell-reasoning_effort="{ row }">
|
||||
<span class="text-sm text-gray-900 dark:text-white">
|
||||
{{ formatReasoningEffort(row.reasoning_effort) }}
|
||||
<div v-if="hasReasoningEffortMapping(row)" class="space-y-0.5 text-xs">
|
||||
<div class="font-medium text-gray-900 dark:text-white">
|
||||
{{ formatReasoningEffort(row.requested_reasoning_effort) }}
|
||||
</div>
|
||||
<div class="text-gray-500 dark:text-gray-400">
|
||||
<span class="mr-0.5">↳</span>{{ formatReasoningEffort(row.reasoning_effort) }}
|
||||
</div>
|
||||
</div>
|
||||
<span v-else class="text-sm text-gray-900 dark:text-white">
|
||||
{{ formatReasoningEffort(row.requested_reasoning_effort || row.reasoning_effort) }}
|
||||
</span>
|
||||
</template>
|
||||
|
||||
@@ -500,7 +508,7 @@
|
||||
import { computed, ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useAppStore } from '@/stores/app'
|
||||
import { formatDateTime, formatReasoningEffort } from '@/utils/format'
|
||||
import { formatDateTime, formatReasoningEffort, reasoningEffortValuesEqual } from '@/utils/format'
|
||||
import { formatCacheTokens, formatMultiplier } from '@/utils/formatters'
|
||||
import { formatTokenPricePerMillion } from '@/utils/usagePricing'
|
||||
import { getUsageServiceTierLabel } from '@/utils/usageServiceTier'
|
||||
@@ -587,6 +595,12 @@ const ipGeoBatchLoading = ref(false)
|
||||
|
||||
const showIpGeoToolbar = computed(() => props.columns.some((col) => col.key === 'ip_address'))
|
||||
|
||||
const hasReasoningEffortMapping = (row: AdminUsageLog): boolean => {
|
||||
const requested = row.requested_reasoning_effort?.trim() || ''
|
||||
const forwarded = row.reasoning_effort?.trim() || ''
|
||||
return requested !== '' && forwarded !== '' && !reasoningEffortValuesEqual(requested, forwarded)
|
||||
}
|
||||
|
||||
const sentUpstreamModel = (row: AdminUsageLog): string => row.upstream_model?.trim() || row.model?.trim() || ''
|
||||
|
||||
const normalizeModelVariant = (model: string): string => model
|
||||
|
||||
@@ -84,6 +84,7 @@ const DataTableStub = {
|
||||
<div>
|
||||
<div v-for="row in data" :key="row.request_id">
|
||||
<slot name="cell-model" :row="row" :value="row.model" />
|
||||
<slot name="cell-reasoning_effort" :row="row" :value="row.reasoning_effort" />
|
||||
<slot name="cell-billing_mode" :row="row" />
|
||||
<slot name="cell-tokens" :row="row" />
|
||||
<slot name="cell-cost" :row="row" />
|
||||
@@ -256,6 +257,61 @@ describe('admin UsageTable tooltip', () => {
|
||||
expect(text).toContain('claude-sonnet-4-20250514')
|
||||
})
|
||||
|
||||
it('shows requested and forwarded reasoning effort separately when they differ', () => {
|
||||
const wrapper = mount(UsageTable, {
|
||||
props: {
|
||||
data: [{
|
||||
request_id: 'req-admin-effort-1',
|
||||
model: 'gpt-5.4',
|
||||
requested_reasoning_effort: 'max',
|
||||
reasoning_effort: 'xhigh',
|
||||
}],
|
||||
loading: false,
|
||||
columns: [],
|
||||
},
|
||||
global: {
|
||||
stubs: {
|
||||
DataTable: DataTableStub,
|
||||
EmptyState: true,
|
||||
Icon: true,
|
||||
Teleport: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
const text = wrapper.text()
|
||||
expect(text).toContain('Max')
|
||||
expect(text).toContain('XHigh')
|
||||
expect(text).toContain('↳')
|
||||
})
|
||||
|
||||
it('shows a single reasoning effort when requested matches forwarded', () => {
|
||||
const wrapper = mount(UsageTable, {
|
||||
props: {
|
||||
data: [{
|
||||
request_id: 'req-admin-effort-2',
|
||||
model: 'gpt-5.6-sol',
|
||||
requested_reasoning_effort: 'max',
|
||||
reasoning_effort: 'max',
|
||||
}],
|
||||
loading: false,
|
||||
columns: [],
|
||||
},
|
||||
global: {
|
||||
stubs: {
|
||||
DataTable: DataTableStub,
|
||||
EmptyState: true,
|
||||
Icon: true,
|
||||
Teleport: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
const text = wrapper.text()
|
||||
expect(text).toContain('Max')
|
||||
expect(text).not.toContain('↳')
|
||||
})
|
||||
|
||||
it.each([
|
||||
{
|
||||
name: 'possible version variant',
|
||||
@@ -561,6 +617,7 @@ const DataTableStubWithUser = {
|
||||
<div v-for="row in data" :key="row.request_id">
|
||||
<slot name="cell-user" :row="row" />
|
||||
<slot name="cell-model" :row="row" :value="row.model" />
|
||||
<slot name="cell-reasoning_effort" :row="row" :value="row.reasoning_effort" />
|
||||
<slot name="cell-billing_mode" :row="row" />
|
||||
<slot name="cell-tokens" :row="row" />
|
||||
<slot name="cell-cost" :row="row" />
|
||||
|
||||
Reference in New Issue
Block a user