mirror of
https://github.com/fawney19/Aether.git
synced 2026-10-07 01:47:47 +08:00
feat(frontend): Responses WebSocket 配置与用量展示
provider 表单支持开启 Responses WebSocket;用量列表、状态与详情 区分 WebSocket 请求。
This commit is contained in:
@@ -277,6 +277,14 @@
|
||||
>
|
||||
取消
|
||||
</Badge>
|
||||
<Badge
|
||||
v-else-if="isUsageWebSocket(record)"
|
||||
variant="outline"
|
||||
data-usage-transport="websocket"
|
||||
class="whitespace-nowrap border-sky-500/50 text-sky-600 dark:text-sky-400 text-[10px] px-1.5 h-4 leading-4 inline-flex items-center flex-shrink-0"
|
||||
>
|
||||
WS
|
||||
</Badge>
|
||||
<Badge
|
||||
v-else-if="getStreamModeSegments(record).hasConversion"
|
||||
:variant="streamBadgeVariant(getStreamModeSegments(record).client === '流式')"
|
||||
@@ -831,6 +839,14 @@
|
||||
>
|
||||
已取消
|
||||
</Badge>
|
||||
<Badge
|
||||
v-else-if="isUsageWebSocket(record)"
|
||||
variant="outline"
|
||||
data-usage-transport="websocket"
|
||||
class="whitespace-nowrap border-sky-500/50 text-sky-600 dark:text-sky-400"
|
||||
>
|
||||
WS
|
||||
</Badge>
|
||||
<Badge
|
||||
v-else-if="getStreamModeSegments(record).hasConversion"
|
||||
:variant="streamBadgeVariant(getStreamModeSegments(record).client === '流式')"
|
||||
@@ -1022,6 +1038,7 @@ import {
|
||||
formatUsageStreamLabel,
|
||||
isUsageRecordFailed,
|
||||
isUsageUpstreamStream,
|
||||
isUsageWebSocket,
|
||||
resolveDisplayRequestStatus,
|
||||
resolveUsageStreamLabelSegments
|
||||
} from '../utils/status'
|
||||
|
||||
@@ -342,6 +342,17 @@ describe('UsageRecordsTable', () => {
|
||||
expect(root.textContent).toContain('gpt-5')
|
||||
})
|
||||
|
||||
it('shows WS in the type column for completed WebSocket usage records', () => {
|
||||
const root = mountUsageRecordsTable([buildRecord({
|
||||
is_websocket: true,
|
||||
status: 'completed',
|
||||
})])
|
||||
|
||||
const badges = [...root.querySelectorAll<HTMLElement>('[data-usage-transport="websocket"]')]
|
||||
expect(badges.length).toBeGreaterThan(0)
|
||||
expect(badges.every(badge => badge.textContent?.trim() === 'WS')).toBe(true)
|
||||
})
|
||||
|
||||
it('shows reasoning effort next to the model name', () => {
|
||||
const root = mountUsageRecordsTable([buildRecord({
|
||||
requested_reasoning_effort: 'xhigh',
|
||||
|
||||
@@ -647,6 +647,7 @@ export function useUsageData(options: UseUsageDataOptions) {
|
||||
? (record.image_progress ?? existing.image_progress)
|
||||
: existing.image_progress,
|
||||
is_stream: upstreamIsStream,
|
||||
is_websocket: mergeBooleanTrueWins(existing.is_websocket, record.is_websocket),
|
||||
upstream_is_stream: upstreamIsStream,
|
||||
client_requested_stream: clientRequestedStream,
|
||||
client_is_stream: clientIsStream,
|
||||
|
||||
@@ -120,6 +120,7 @@ export interface UsageRecord {
|
||||
end_to_end_time_ms?: number | null // 客户端从请求进入网关到完成的总耗时
|
||||
end_to_end_first_byte_time_ms?: number | null // 客户端从请求进入网关到首字节的耗时
|
||||
is_stream: boolean
|
||||
is_websocket?: boolean
|
||||
upstream_is_stream?: boolean
|
||||
client_requested_stream?: boolean
|
||||
client_is_stream?: boolean
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
hasUsageRetry,
|
||||
isUsageRecordFailed,
|
||||
isUsageRecordSuccessful,
|
||||
isUsageWebSocket,
|
||||
mapRequestStatusToTimelineStatus,
|
||||
normalizeRequestStatus,
|
||||
resolveDisplayRequestStatus,
|
||||
@@ -177,6 +178,12 @@ describe('usage status helpers', () => {
|
||||
expect(hasUsageRetry(buildUsageRecord({ has_retry: undefined }))).toBe(false)
|
||||
})
|
||||
|
||||
it('recognizes persisted WebSocket usage records', () => {
|
||||
expect(isUsageWebSocket(buildUsageRecord({ is_websocket: true }))).toBe(true)
|
||||
expect(isUsageWebSocket(buildUsageRecord({ is_websocket: false }))).toBe(false)
|
||||
expect(isUsageWebSocket(buildUsageRecord({ is_websocket: undefined }))).toBe(false)
|
||||
})
|
||||
|
||||
it('prefers symmetric stream aliases when present', () => {
|
||||
expect(formatUsageStreamLabel(buildUsageRecord({
|
||||
is_stream: true,
|
||||
|
||||
@@ -49,6 +49,12 @@ export function hasUsageRetry(
|
||||
return record.has_retry === true
|
||||
}
|
||||
|
||||
export function isUsageWebSocket(
|
||||
record: Pick<UsageRecord, 'is_websocket'>
|
||||
): boolean {
|
||||
return record.is_websocket === true
|
||||
}
|
||||
|
||||
export function resolveUsageStreamModes(
|
||||
record: Pick<
|
||||
UsageRecord,
|
||||
|
||||
Reference in New Issue
Block a user