migrate ai format conversion to responses adapters

This commit is contained in:
fawney19
2026-04-26 20:32:55 +08:00
parent e36fb8c07a
commit 5b914aa78c
183 changed files with 13539 additions and 3401 deletions

View File

@@ -687,7 +687,7 @@ interface ApiFormatGroup {
const STANDARD_ROUTING_API_FORMATS = [
'openai:chat',
'openai:cli',
'openai:responses',
'claude:chat',
'claude:cli',
'gemini:chat',
@@ -704,6 +704,8 @@ function apiDataFormatId(apiFormat: string): string | null {
return 'gemini'
case 'openai:chat':
return 'openai_chat'
case 'openai:responses':
case 'openai:responses:compact':
case 'openai:cli':
case 'openai:compact':
return 'openai_responses'
@@ -723,8 +725,10 @@ function requestConversionKind(clientApiFormat: string, providerApiFormat: strin
switch (provider) {
case 'openai:chat':
return 'to_openai_chat'
case 'openai:responses':
return 'to_openai_responses'
case 'openai:cli':
return 'to_openai_cli'
return 'to_openai_responses'
case 'claude:chat':
case 'claude:cli':
return 'to_claude'

View File

@@ -1336,7 +1336,7 @@ function getDefaultPath(apiFormat: string, baseUrl?: string): string {
const isCodex = providerType
? providerType === 'codex'
: (!!baseUrl && isCodexUrl(baseUrl))
if (apiFormat === 'openai:cli' && isCodex) {
if ((apiFormat === 'openai:responses' || apiFormat === 'openai:cli') && isCodex) {
return '/responses'
}
return defaultPath
@@ -2381,7 +2381,7 @@ function getCurrentUpstreamStreamPolicy(endpoint: ProviderEndpoint): string {
function isUpstreamStreamPolicyLocked(endpoint: ProviderEndpoint): boolean {
return (props.provider?.provider_type || '').toLowerCase() === 'codex'
&& endpoint.api_format === 'openai:cli'
&& (endpoint.api_format === 'openai:responses' || endpoint.api_format === 'openai:cli')
}
// 获取上游流式按钮的样式类
@@ -2398,7 +2398,7 @@ function getUpstreamStreamButtonClass(endpoint: ProviderEndpoint): string {
// 获取上游流式按钮的提示文字
function getUpstreamStreamTooltip(endpoint: ProviderEndpoint): string {
if (isUpstreamStreamPolicyLocked(endpoint)) return '固定流式Codex OpenAI CLI已锁定'
if (isUpstreamStreamPolicyLocked(endpoint)) return '固定流式Codex OpenAI Responses已锁定'
const policy = getCurrentUpstreamStreamPolicy(endpoint)
if (policy === 'force_stream') return '固定流式点击切换为固定非流'
if (policy === 'force_non_stream') return '固定非流点击切换为跟随请求'

View File

@@ -611,8 +611,10 @@ const LEGACY_API_FORMAT_MAP: Record<string, string> = {
CLAUDE: 'claude:chat',
CLAUDE_CLI: 'claude:cli',
OPENAI: 'openai:chat',
OPENAI_CLI: 'openai:cli',
OPENAI_COMPACT: 'openai:compact',
OPENAI_CLI: 'openai:responses',
OPENAI_COMPACT: 'openai:responses:compact',
OPENAI_RESPONSES: 'openai:responses',
OPENAI_RESPONSES_COMPACT: 'openai:responses:compact',
OPENAI_VIDEO: 'openai:video',
GEMINI: 'gemini:chat',
GEMINI_CLI: 'gemini:cli',

View File

@@ -7,8 +7,8 @@ const ENDPOINT_SORT_ORDER = [
'claude:chat',
'claude:cli',
'openai:chat',
'openai:cli',
'openai:compact',
'openai:responses',
'openai:responses:compact',
'gemini:chat',
'gemini:cli',
'openai:video',

View File

@@ -26,8 +26,8 @@ export function useProviderFilters(
{ value: 'claude:chat', label: 'Claude Chat' },
{ value: 'claude:cli', label: 'Claude CLI' },
{ value: 'openai:chat', label: 'OpenAI Chat' },
{ value: 'openai:cli', label: 'OpenAI CLI' },
{ value: 'openai:compact', label: 'OpenAI Compact' },
{ value: 'openai:responses', label: 'OpenAI Responses' },
{ value: 'openai:responses:compact', label: 'OpenAI Responses Compact' },
{ value: 'gemini:chat', label: 'Gemini Chat' },
{ value: 'gemini:cli', label: 'Gemini CLI' },
]

View File

@@ -546,7 +546,7 @@ interface NodeGroup {
startIndex: number
endIndex: number
hasConversion: boolean // 组内是否有格式转换候选
providerApiFormat: string | null // 提供商 API 格式(如 openai:cli
providerApiFormat: string | null // 提供商 API 格式(如 openai:responses
isPoolGroup?: boolean
}

View File

@@ -754,8 +754,8 @@ const emit = defineEmits<{
// 静态常量(放在 defineProps/defineEmits 之后)
const AVAILABLE_API_FORMATS = [
{ value: 'openai:chat', label: 'OpenAI Chat' },
{ value: 'openai:cli', label: 'OpenAI CLI' },
{ value: 'openai:compact', label: 'OpenAI Compact' },
{ 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' },

View File

@@ -114,7 +114,7 @@ export class OpenAIParser implements ApiFormatParser {
if (model.includes('gpt') || model.includes('o1') || model.includes('o3')) return 95
// 3. 检查请求体结构
// OpenAI CLI (Responses API) 使用 input 字段
// OpenAI Responses API 使用 input 字段
const isCliFormat = req?.input !== undefined || req?.instructions !== undefined
// OpenAI Chat Completions 使用 messages 数组
const isChatFormat = req?.messages && Array.isArray(req.messages)
@@ -129,7 +129,7 @@ export class OpenAIParser implements ApiFormatParser {
: responseBody) as RawObject | null | undefined
if (respBody) {
// OpenAI CLI 响应特征: type 字段为 response.* 格式
// OpenAI Responses 响应特征: type 字段为 response.* 格式
if (this.isCliResponseEvent(respBody)) {
return 95
}
@@ -163,7 +163,7 @@ export class OpenAIParser implements ApiFormatParser {
}
/**
* 检查是否为 OpenAI CLI (Responses API) 的响应事件
* 检查是否为 OpenAI Responses API 的响应事件
*/
private isCliResponseEvent(chunk: RawObject | null | undefined): boolean {
const type = chunk?.type
@@ -231,7 +231,7 @@ export class OpenAIParser implements ApiFormatParser {
}
/**
* 解析 OpenAI CLI (Responses API) 请求
* 解析 OpenAI Responses API 请求
*
* CLI 格式特点:
* - 使用 input 字段(可以是字符串、消息数组或对象)
@@ -404,7 +404,7 @@ export class OpenAIParser implements ApiFormatParser {
}
/**
* 解析 OpenAI CLI (Responses API) 响应
* 解析 OpenAI Responses API 响应
*
* CLI 响应格式: { output: [{ type: "message", content: [...] }] }
*/
@@ -548,7 +548,7 @@ export class OpenAIParser implements ApiFormatParser {
}
/**
* 解析 OpenAI CLI (Responses API) 流式响应
* 解析 OpenAI Responses API 流式响应
*
* 支持的事件类型:
* - response.created: 响应创建
@@ -809,7 +809,7 @@ export class OpenAIParser implements ApiFormatParser {
}
/**
* 渲染 OpenAI CLI (Responses API) 请求
* 渲染 OpenAI Responses API 请求
*/
private renderCliRequest(requestBody: RawObject): RenderResult {
try {
@@ -985,7 +985,7 @@ export class OpenAIParser implements ApiFormatParser {
}
/**
* 渲染 OpenAI CLI (Responses API) 响应
* 渲染 OpenAI Responses API 响应
*/
private renderCliResponse(responseBody: RawObject): RenderResult {
try {

View File

@@ -136,6 +136,8 @@ function normalizeUsageStreamApiFormat(value: string | null | undefined): string
function usageApiFormatDefaultsToNonStream(apiFormat: string): boolean {
switch (apiFormat) {
case 'openai:chat':
case 'openai:responses':
case 'openai:responses:compact':
case 'openai:cli':
case 'openai:compact':
case 'openai:image':