Normalize canonical API formats

This commit is contained in:
fawney19
2026-04-29 09:25:19 +08:00
parent 02ad67fe33
commit 07a319259b
171 changed files with 2460 additions and 1962 deletions

View File

@@ -25,7 +25,7 @@ describe('usage token normalization', () => {
cache_creation_input_tokens: 1530,
cache_read_input_tokens: 104026,
output_tokens: 591,
api_format: 'claude:chat',
api_format: 'claude:messages',
}
expect(getEffectiveInputTokens(usage)).toBe(1)
@@ -47,7 +47,7 @@ describe('usage token normalization', () => {
cache_creation_input_tokens: 687,
cache_read_input_tokens: 52873,
output_tokens: 973,
api_format: 'claude:chat',
api_format: 'claude:messages',
})).toBe(4941)
})
})

View File

@@ -757,11 +757,10 @@ const AVAILABLE_API_FORMATS = [
{ value: 'openai:responses', label: 'OpenAI Responses' },
{ value: 'openai:responses:compact', label: 'OpenAI Responses Compact' },
{ value: 'openai:video', label: 'OpenAI Video' },
{ value: 'claude:chat', label: 'Claude Chat' },
{ value: 'claude:cli', label: 'Claude CLI' },
{ value: 'gemini:chat', label: 'Gemini Chat' },
{ value: 'gemini:cli', label: 'Gemini CLI' },
{ value: 'claude:messages', label: 'Claude Messages' },
{ value: 'gemini:generate_content', label: 'Gemini Generate Content' },
{ value: 'gemini:video', label: 'Gemini Video' },
{ value: 'gemini:files', label: 'Gemini Files' },
] as const
// 使用模块级常量
@@ -844,7 +843,7 @@ function formatOptionalTokens(value: number | null | undefined): string {
// useDebounceFn 自动处理清理,无需 onUnmounted
// 判断是否应该显示格式转换信息
// 包括1. 跨格式转换has_format_conversion=true2. 同族格式差异(如 CLAUDE_CLI → CLAUDE
// 包括1. 跨格式转换has_format_conversion=true2. 同族格式差异
function shouldShowFormatConversion(record: UsageRecord): boolean {
if (!record.api_format || !record.endpoint_api_format) {
return false

View File

@@ -20,7 +20,7 @@ describe('Gemini conversation parser', () => {
}
it('parses normalized output payload when hint is gemini', () => {
const parsed = parseResponse(normalizedResponse, requestBody, 'gemini:chat')
const parsed = parseResponse(normalizedResponse, requestBody, 'gemini:generate_content')
expect(parsed.apiFormat).toBe('gemini')
expect(parsed.messages).toHaveLength(1)
expect(parsed.messages[0]?.role).toBe('assistant')
@@ -31,7 +31,7 @@ describe('Gemini conversation parser', () => {
})
it('renders normalized output payload when hint is gemini', () => {
const rendered = renderResponse(normalizedResponse, requestBody, 'gemini:chat')
const rendered = renderResponse(normalizedResponse, requestBody, 'gemini:generate_content')
expect(rendered.error).toBeUndefined()
expect(rendered.blocks).toHaveLength(1)
expect(rendered.blocks[0]).toMatchObject({

View File

@@ -135,7 +135,7 @@ describe('usage status helpers', () => {
it('defaults OpenAI and Claude requests to non-stream when client flags are absent', () => {
expect(formatUsageStreamLabel(buildUsageRecord({
api_format: 'openai:cli',
api_format: 'openai:responses',
is_stream: true,
upstream_is_stream: true,
client_requested_stream: undefined,
@@ -143,7 +143,7 @@ describe('usage status helpers', () => {
}))).toBe('标准->流式')
expect(formatUsageStreamLabel(buildUsageRecord({
api_format: 'claude:chat',
api_format: 'claude:messages',
is_stream: false,
upstream_is_stream: false,
client_requested_stream: undefined,
@@ -153,7 +153,7 @@ describe('usage status helpers', () => {
it('keeps upstream fallback for formats without a default non-stream convention', () => {
expect(formatUsageStreamLabel(buildUsageRecord({
api_format: 'gemini:cli',
api_format: 'gemini:generate_content',
is_stream: true,
upstream_is_stream: true,
client_requested_stream: undefined,
@@ -163,7 +163,7 @@ describe('usage status helpers', () => {
it('prefers client_requested_stream over stale client_is_stream when they disagree', () => {
expect(formatUsageStreamLabel(buildUsageRecord({
api_format: 'openai:cli',
api_format: 'openai:responses',
is_stream: true,
upstream_is_stream: true,
client_requested_stream: false,

View File

@@ -124,14 +124,10 @@ function normalizeUsageStreamApiFormat(value: string | null | undefined): string
switch (normalized) {
case 'openai':
return 'openai:chat'
case 'openai:cli':
return 'openai:responses'
case 'openai:compact':
return 'openai:responses:compact'
case 'claude':
return 'claude:chat'
return 'claude:messages'
case 'gemini':
return 'gemini:chat'
return 'gemini:generate_content'
default:
return normalized
}
@@ -143,8 +139,7 @@ function usageApiFormatDefaultsToNonStream(apiFormat: string): boolean {
case 'openai:responses':
case 'openai:responses:compact':
case 'openai:image':
case 'claude:chat':
case 'claude:cli':
case 'claude:messages':
return true
default:
return false