feat(stream-bridge): 支持上游 sync 响应转 SSE 流式输出,记录 client/upstream 流模式差异

- 新增 sync_to_stream 桥接模块,将非 SSE 上游响应转换为 SSE 格式回传给流式客户端
- stream_pump 检测非 SSE 响应头后缓冲整包并通过桥接逻辑重写为 SSE 帧
- proxy handler 同步支持 sync→stream 聚合与转换(覆盖 openai/claude/gemini 四种格式)
- sync_products 补全 openai:cli 的完整流式事件聚合(text delta、reasoning、tool call 等)
- usage runtime 写入 client_requested_stream / upstream_is_stream 到 request_metadata
- SQL 查询层将两个布尔字段从 request_metadata jsonb 中提取并回传给前端
- 前端 status.ts 新增 resolveUsageStreamLabelSegments,优先读取 client_requested_stream
- RequestDetailDrawer 在流式转换场景下显示"客户端→上游"两段 Badge
This commit is contained in:
fawney19
2026-04-23 21:53:50 +08:00
parent 40282c3447
commit 342d4a268c
40 changed files with 3638 additions and 97 deletions
@@ -232,6 +232,17 @@
>
取消
</Badge>
<Badge
v-else-if="getStreamModeSegments(record).hasConversion"
:variant="getStreamModeSegments(record).client === '流式' ? 'secondary' : 'outline'"
:class="getStreamModeSegments(record).client === '流式'
? 'whitespace-nowrap text-[10px] px-1.5 h-4 leading-4 inline-flex items-center gap-0.5'
: 'whitespace-nowrap border-border/60 text-muted-foreground text-[10px] px-1.5 h-4 leading-4 inline-flex items-center gap-0.5'"
>
<span>{{ getStreamModeSegments(record).client }}</span>
<span class="opacity-60">→</span>
<span>{{ getStreamModeSegments(record).upstream }}</span>
</Badge>
<Badge
v-else
:variant="getUpstreamStream(record) ? 'secondary' : 'outline'"
@@ -529,6 +540,17 @@
>
已取消
</Badge>
<Badge
v-else-if="getStreamModeSegments(record).hasConversion"
:variant="getStreamModeSegments(record).client === '流式' ? 'secondary' : 'outline'"
:class="getStreamModeSegments(record).client === '流式'
? 'whitespace-nowrap inline-flex items-center gap-1'
: 'whitespace-nowrap border-border/60 text-muted-foreground inline-flex items-center gap-1'"
>
<span>{{ getStreamModeSegments(record).client }}</span>
<span class="opacity-60">→</span>
<span>{{ getStreamModeSegments(record).upstream }}</span>
</Badge>
<Badge
v-else
:variant="getUpstreamStream(record) ? 'secondary' : 'outline'"
@@ -672,7 +694,8 @@ import {
formatUsageStreamLabel,
isUsageRecordFailed,
isUsageUpstreamStream,
resolveDisplayRequestStatus
resolveDisplayRequestStatus,
resolveUsageStreamLabelSegments
} from '../utils/status'
import { useRowClick } from '@/composables/useRowClick'
import { formatApiFormat } from '@/api/endpoints/types/api-format'
@@ -763,6 +786,10 @@ function getStreamModeLabel(record: UsageRecord): string {
return formatUsageStreamLabel(record)
}
function getStreamModeSegments(record: UsageRecord) {
return resolveUsageStreamLabelSegments(record)
}
function getUpstreamStream(record: UsageRecord): boolean {
return isUsageUpstreamStream(record)
}