mirror of
https://github.com/fawney19/Aether.git
synced 2026-10-11 11:49:50 +08:00
Normalize canonical API formats
This commit is contained in:
@@ -39,8 +39,8 @@ fn encode_frame(headers: Vec<u8>, payload: Vec<u8>) -> Vec<u8> {
|
||||
|
||||
fn kiro_report_context(thinking_enabled: bool) -> Value {
|
||||
let mut context = json!({
|
||||
"provider_api_format": "claude:cli",
|
||||
"client_api_format": "claude:cli",
|
||||
"provider_api_format": "claude:messages",
|
||||
"client_api_format": "claude:messages",
|
||||
"envelope_name": "kiro:generateAssistantResponse",
|
||||
"mapped_model": "claude-sonnet-4.5"
|
||||
});
|
||||
|
||||
@@ -9,7 +9,7 @@ fn normalizes_supported_private_report_context() {
|
||||
let report_context = json!({
|
||||
"has_envelope": true,
|
||||
"envelope_name": "antigravity:v1internal",
|
||||
"provider_api_format": "gemini:cli",
|
||||
"provider_api_format": "gemini:generate_content",
|
||||
});
|
||||
let normalized = normalize_provider_private_report_context(Some(&report_context))
|
||||
.expect("context should normalize");
|
||||
@@ -21,8 +21,8 @@ fn normalizes_supported_private_report_context() {
|
||||
fn private_stream_normalizer_unwraps_antigravity_stream() {
|
||||
let report_context = json!({
|
||||
"has_envelope": true,
|
||||
"provider_api_format": "gemini:cli",
|
||||
"client_api_format": "gemini:cli",
|
||||
"provider_api_format": "gemini:generate_content",
|
||||
"client_api_format": "gemini:generate_content",
|
||||
"envelope_name": "antigravity:v1internal",
|
||||
"mapped_model": "claude-sonnet-4-5",
|
||||
});
|
||||
|
||||
@@ -30,7 +30,7 @@ mod tests {
|
||||
Some(RequestConversionKind::ToOpenAiResponses)
|
||||
);
|
||||
assert_eq!(
|
||||
request_conversion_kind("openai:chat", "claude:cli"),
|
||||
request_conversion_kind("openai:chat", "claude:messages"),
|
||||
Some(RequestConversionKind::ToClaudeStandard)
|
||||
);
|
||||
assert_eq!(
|
||||
@@ -38,56 +38,59 @@ mod tests {
|
||||
Some(RequestConversionKind::ToOpenAIChat)
|
||||
);
|
||||
assert_eq!(
|
||||
request_conversion_kind("gemini:chat", "claude:chat"),
|
||||
request_conversion_kind("gemini:generate_content", "claude:messages"),
|
||||
Some(RequestConversionKind::ToClaudeStandard)
|
||||
);
|
||||
assert_eq!(
|
||||
request_conversion_kind("openai:responses:compact", "gemini:cli"),
|
||||
request_conversion_kind("openai:responses:compact", "gemini:generate_content"),
|
||||
None
|
||||
);
|
||||
assert_eq!(
|
||||
request_conversion_kind("gemini:cli", "openai:responses:compact"),
|
||||
request_conversion_kind("gemini:generate_content", "openai:responses:compact"),
|
||||
None
|
||||
);
|
||||
assert_eq!(
|
||||
request_conversion_kind("openai:chat", "openai:responses:compact"),
|
||||
None
|
||||
);
|
||||
assert_eq!(request_conversion_kind("claude:chat", "claude:chat"), None);
|
||||
assert_eq!(
|
||||
request_conversion_kind("claude:messages", "claude:messages"),
|
||||
None
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sync_response_conversion_registry_supports_bidirectional_standard_matrix() {
|
||||
assert_eq!(
|
||||
sync_chat_response_conversion_kind("openai:chat", "claude:chat"),
|
||||
sync_chat_response_conversion_kind("openai:chat", "claude:messages"),
|
||||
Some(SyncChatResponseConversionKind::ToClaudeChat)
|
||||
);
|
||||
assert_eq!(
|
||||
sync_chat_response_conversion_kind("claude:chat", "gemini:chat"),
|
||||
sync_chat_response_conversion_kind("claude:messages", "gemini:generate_content"),
|
||||
Some(SyncChatResponseConversionKind::ToGeminiChat)
|
||||
);
|
||||
assert_eq!(
|
||||
sync_chat_response_conversion_kind("gemini:chat", "openai:chat"),
|
||||
sync_chat_response_conversion_kind("gemini:generate_content", "openai:chat"),
|
||||
Some(SyncChatResponseConversionKind::ToOpenAIChat)
|
||||
);
|
||||
assert_eq!(
|
||||
sync_cli_response_conversion_kind("openai:responses", "gemini:cli"),
|
||||
sync_cli_response_conversion_kind("openai:responses", "gemini:generate_content"),
|
||||
Some(SyncCliResponseConversionKind::ToGeminiCli)
|
||||
);
|
||||
assert_eq!(
|
||||
sync_cli_response_conversion_kind("claude:chat", "openai:responses"),
|
||||
sync_cli_response_conversion_kind("claude:messages", "openai:responses"),
|
||||
Some(SyncCliResponseConversionKind::ToOpenAiResponses)
|
||||
);
|
||||
assert_eq!(
|
||||
sync_cli_response_conversion_kind("claude:cli", "openai:responses:compact"),
|
||||
sync_cli_response_conversion_kind("claude:messages", "openai:responses:compact"),
|
||||
Some(SyncCliResponseConversionKind::ToOpenAiResponses)
|
||||
);
|
||||
assert_eq!(
|
||||
sync_cli_response_conversion_kind("openai:responses:compact", "claude:cli"),
|
||||
sync_cli_response_conversion_kind("openai:responses:compact", "claude:messages"),
|
||||
None
|
||||
);
|
||||
assert_eq!(
|
||||
sync_cli_response_conversion_kind("gemini:cli", "claude:cli"),
|
||||
sync_cli_response_conversion_kind("gemini:generate_content", "claude:messages"),
|
||||
Some(SyncCliResponseConversionKind::ToClaudeCli)
|
||||
);
|
||||
}
|
||||
@@ -98,49 +101,31 @@ mod tests {
|
||||
request_candidate_api_formats("openai:chat", false),
|
||||
vec![
|
||||
"openai:chat",
|
||||
"claude:chat",
|
||||
"gemini:chat",
|
||||
"openai:responses",
|
||||
"claude:cli",
|
||||
"gemini:cli",
|
||||
"claude:messages",
|
||||
"gemini:generate_content",
|
||||
]
|
||||
);
|
||||
assert_eq!(
|
||||
request_candidate_api_formats("openai:responses", false),
|
||||
vec![
|
||||
"openai:responses",
|
||||
"claude:cli",
|
||||
"gemini:cli",
|
||||
"openai:chat",
|
||||
"claude:chat",
|
||||
"gemini:chat",
|
||||
"claude:messages",
|
||||
"gemini:generate_content",
|
||||
]
|
||||
);
|
||||
assert_eq!(
|
||||
request_candidate_api_formats("openai:cli", false),
|
||||
vec![
|
||||
"openai:responses",
|
||||
"claude:cli",
|
||||
"gemini:cli",
|
||||
"openai:chat",
|
||||
"claude:chat",
|
||||
"gemini:chat",
|
||||
]
|
||||
Vec::<&'static str>::new()
|
||||
);
|
||||
assert_eq!(
|
||||
request_candidate_api_formats("claude:cli", false),
|
||||
vec![
|
||||
"claude:cli",
|
||||
"openai:responses",
|
||||
"gemini:cli",
|
||||
"claude:chat",
|
||||
"openai:chat",
|
||||
"gemini:chat",
|
||||
]
|
||||
Vec::<&'static str>::new()
|
||||
);
|
||||
assert_eq!(
|
||||
request_candidate_api_formats("openai:compact", false),
|
||||
vec!["openai:responses:compact"]
|
||||
Vec::<&'static str>::new()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -148,15 +133,15 @@ mod tests {
|
||||
fn request_candidate_registry_prefers_same_kind_before_same_family_fallbacks() {
|
||||
assert_eq!(
|
||||
request_candidate_api_format_preference("claude:cli", "openai:responses"),
|
||||
Some((1, 0))
|
||||
None
|
||||
);
|
||||
assert_eq!(
|
||||
request_candidate_api_format_preference("claude:cli", "claude:chat"),
|
||||
Some((2, 1))
|
||||
None
|
||||
);
|
||||
assert_eq!(
|
||||
request_candidate_api_format_preference("claude:cli", "openai:chat"),
|
||||
Some((3, 0))
|
||||
None
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,7 +110,7 @@ fn maybe_bridge_openai_image_sync_json_to_stream(
|
||||
}
|
||||
|
||||
fn normalize_api_format(value: &str) -> String {
|
||||
crate::ai_pipeline::normalize_legacy_openai_format_alias(value)
|
||||
crate::ai_pipeline::normalize_api_format_alias(value)
|
||||
}
|
||||
|
||||
fn is_standard_api_format(value: &str) -> bool {
|
||||
@@ -119,10 +119,8 @@ fn is_standard_api_format(value: &str) -> bool {
|
||||
"openai:chat"
|
||||
| "openai:responses"
|
||||
| "openai:responses:compact"
|
||||
| "claude:chat"
|
||||
| "claude:cli"
|
||||
| "gemini:chat"
|
||||
| "gemini:cli"
|
||||
| "claude:messages"
|
||||
| "gemini:generate_content"
|
||||
)
|
||||
}
|
||||
|
||||
@@ -210,10 +208,10 @@ fn convert_provider_sync_response_to_openai_responses(
|
||||
report_context,
|
||||
false,
|
||||
),
|
||||
"claude:chat" | "claude:cli" => {
|
||||
"claude:messages" => {
|
||||
convert_claude_response_to_openai_responses(provider_body_json, report_context)
|
||||
}
|
||||
"gemini:chat" | "gemini:cli" => {
|
||||
"gemini:generate_content" => {
|
||||
convert_gemini_response_to_openai_responses(provider_body_json, report_context)
|
||||
}
|
||||
_ => None,
|
||||
@@ -257,11 +255,11 @@ fn emit_client_stream_from_canonical_frames(
|
||||
let mut emitter = OpenAIResponsesClientEmitter::default();
|
||||
emit_with_openai_responses_emitter(&mut emitter, canonical_frames)
|
||||
}
|
||||
"claude:chat" | "claude:cli" => {
|
||||
"claude:messages" => {
|
||||
let mut emitter = ClaudeClientEmitter::default();
|
||||
emit_with_claude_emitter(&mut emitter, canonical_frames)
|
||||
}
|
||||
"gemini:chat" | "gemini:cli" => {
|
||||
"gemini:generate_content" => {
|
||||
let mut emitter = GeminiClientEmitter::default();
|
||||
emit_with_gemini_emitter(&mut emitter, canonical_frames)
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ fn standard_sync_bridge_converts_claude_sync_json_to_openai_responses_sse() {
|
||||
"output_tokens": 3
|
||||
}
|
||||
}),
|
||||
"claude:chat",
|
||||
"claude:messages",
|
||||
"openai:responses",
|
||||
Some(&report_context),
|
||||
)
|
||||
@@ -111,8 +111,8 @@ fn standard_sync_bridge_converts_claude_sync_json_to_openai_responses_sse() {
|
||||
fn antigravity_stream_rewriter_unwraps_and_injects_tool_ids() {
|
||||
let report_context = json!({
|
||||
"has_envelope": true,
|
||||
"provider_api_format": "gemini:cli",
|
||||
"client_api_format": "gemini:cli",
|
||||
"provider_api_format": "gemini:generate_content",
|
||||
"client_api_format": "gemini:generate_content",
|
||||
"envelope_name": "antigravity:v1internal",
|
||||
"needs_conversion": false,
|
||||
"mapped_model": "claude-sonnet-4-5",
|
||||
@@ -378,8 +378,8 @@ fn openai_image_stream_rewriter_emits_partial_and_completed_events_for_edit() {
|
||||
fn gemini_cli_v1internal_stream_rewriter_unwraps_response_object() {
|
||||
let report_context = json!({
|
||||
"has_envelope": true,
|
||||
"provider_api_format": "gemini:cli",
|
||||
"client_api_format": "gemini:cli",
|
||||
"provider_api_format": "gemini:generate_content",
|
||||
"client_api_format": "gemini:generate_content",
|
||||
"envelope_name": "gemini_cli:v1internal",
|
||||
"needs_conversion": false,
|
||||
});
|
||||
@@ -424,7 +424,7 @@ fn openai_chat_error_to_openai_responses_stream_rewriter_converts_to_response_fa
|
||||
#[test]
|
||||
fn claude_error_to_openai_responses_stream_rewriter_converts_to_response_failed() {
|
||||
let report_context = json!({
|
||||
"provider_api_format": "claude:chat",
|
||||
"provider_api_format": "claude:messages",
|
||||
"client_api_format": "openai:responses",
|
||||
"needs_conversion": true,
|
||||
"mapped_model": "claude-sonnet-4-5",
|
||||
@@ -452,7 +452,7 @@ fn claude_error_to_openai_responses_stream_rewriter_converts_to_response_failed(
|
||||
#[test]
|
||||
fn gemini_error_to_openai_responses_stream_rewriter_converts_to_response_failed() {
|
||||
let report_context = json!({
|
||||
"provider_api_format": "gemini:cli",
|
||||
"provider_api_format": "gemini:generate_content",
|
||||
"client_api_format": "openai:responses",
|
||||
"needs_conversion": true,
|
||||
"mapped_model": "gemini-2.5-pro",
|
||||
@@ -477,7 +477,7 @@ fn gemini_error_to_openai_responses_stream_rewriter_converts_to_response_failed(
|
||||
fn openai_chat_error_to_claude_chat_stream_rewriter_uses_error_event_line() {
|
||||
let report_context = json!({
|
||||
"provider_api_format": "openai:chat",
|
||||
"client_api_format": "claude:chat",
|
||||
"client_api_format": "claude:messages",
|
||||
"needs_conversion": true,
|
||||
"mapped_model": "gpt-5.4",
|
||||
});
|
||||
@@ -501,7 +501,7 @@ fn openai_chat_error_to_claude_chat_stream_rewriter_uses_error_event_line() {
|
||||
fn openai_chat_error_to_gemini_chat_stream_rewriter_keeps_data_only_error() {
|
||||
let report_context = json!({
|
||||
"provider_api_format": "openai:chat",
|
||||
"client_api_format": "gemini:chat",
|
||||
"client_api_format": "gemini:generate_content",
|
||||
"needs_conversion": true,
|
||||
"mapped_model": "gpt-5.4",
|
||||
});
|
||||
@@ -524,7 +524,7 @@ fn openai_chat_error_to_gemini_chat_stream_rewriter_keeps_data_only_error() {
|
||||
#[test]
|
||||
fn claude_to_openai_chat_stream_rewriter_converts_text_deltas() {
|
||||
let report_context = json!({
|
||||
"provider_api_format": "claude:chat",
|
||||
"provider_api_format": "claude:messages",
|
||||
"client_api_format": "openai:chat",
|
||||
"needs_conversion": true,
|
||||
"mapped_model": "claude-sonnet-4-5",
|
||||
@@ -557,7 +557,7 @@ fn claude_to_openai_chat_stream_rewriter_converts_text_deltas() {
|
||||
#[test]
|
||||
fn claude_to_openai_chat_stream_rewriter_converts_tool_use_to_tool_calls() {
|
||||
let report_context = json!({
|
||||
"provider_api_format": "claude:chat",
|
||||
"provider_api_format": "claude:messages",
|
||||
"client_api_format": "openai:chat",
|
||||
"needs_conversion": true,
|
||||
"mapped_model": "claude-sonnet-4-5",
|
||||
@@ -597,7 +597,7 @@ fn claude_to_openai_chat_stream_rewriter_converts_tool_use_to_tool_calls() {
|
||||
#[test]
|
||||
fn gemini_to_openai_chat_stream_rewriter_buffers_and_converts_text() {
|
||||
let report_context = json!({
|
||||
"provider_api_format": "gemini:chat",
|
||||
"provider_api_format": "gemini:generate_content",
|
||||
"client_api_format": "openai:chat",
|
||||
"needs_conversion": true,
|
||||
"mapped_model": "gemini-2.5-pro",
|
||||
@@ -630,7 +630,7 @@ fn gemini_to_openai_chat_stream_rewriter_buffers_and_converts_text() {
|
||||
#[test]
|
||||
fn gemini_to_openai_chat_stream_rewriter_buffers_and_converts_function_call() {
|
||||
let report_context = json!({
|
||||
"provider_api_format": "gemini:chat",
|
||||
"provider_api_format": "gemini:generate_content",
|
||||
"client_api_format": "openai:chat",
|
||||
"needs_conversion": true,
|
||||
"mapped_model": "gemini-2.5-pro",
|
||||
@@ -761,7 +761,7 @@ fn openai_responses_to_openai_chat_stream_rewriter_converts_completed_event_with
|
||||
#[test]
|
||||
fn antigravity_gemini_to_openai_chat_stream_rewriter_unwraps_and_converts_function_call() {
|
||||
let report_context = json!({
|
||||
"provider_api_format": "gemini:chat",
|
||||
"provider_api_format": "gemini:generate_content",
|
||||
"client_api_format": "openai:chat",
|
||||
"needs_conversion": true,
|
||||
"has_envelope": true,
|
||||
@@ -788,7 +788,7 @@ fn antigravity_gemini_to_openai_chat_stream_rewriter_unwraps_and_converts_functi
|
||||
#[test]
|
||||
fn antigravity_gemini_to_openai_responses_stream_rewriter_unwraps_and_converts_function_call() {
|
||||
let report_context = json!({
|
||||
"provider_api_format": "gemini:cli",
|
||||
"provider_api_format": "gemini:generate_content",
|
||||
"client_api_format": "openai:responses",
|
||||
"needs_conversion": true,
|
||||
"envelope_name": "antigravity:v1internal",
|
||||
@@ -815,7 +815,7 @@ fn antigravity_gemini_to_openai_responses_stream_rewriter_unwraps_and_converts_f
|
||||
#[test]
|
||||
fn gemini_to_openai_responses_stream_rewriter_buffers_and_converts_to_completed_event() {
|
||||
let report_context = json!({
|
||||
"provider_api_format": "gemini:cli",
|
||||
"provider_api_format": "gemini:generate_content",
|
||||
"client_api_format": "openai:responses",
|
||||
"needs_conversion": true,
|
||||
"mapped_model": "gemini-2.5-pro",
|
||||
@@ -850,7 +850,7 @@ fn gemini_to_openai_responses_stream_rewriter_buffers_and_converts_to_completed_
|
||||
#[test]
|
||||
fn claude_to_openai_responses_stream_rewriter_buffers_and_converts_to_completed_event() {
|
||||
let report_context = json!({
|
||||
"provider_api_format": "claude:cli",
|
||||
"provider_api_format": "claude:messages",
|
||||
"client_api_format": "openai:responses",
|
||||
"needs_conversion": true,
|
||||
"mapped_model": "claude-sonnet-4-5",
|
||||
@@ -888,7 +888,7 @@ fn claude_to_openai_responses_stream_rewriter_buffers_and_converts_to_completed_
|
||||
#[test]
|
||||
fn claude_to_openai_responses_stream_rewriter_converts_tool_use_to_function_call() {
|
||||
let report_context = json!({
|
||||
"provider_api_format": "claude:cli",
|
||||
"provider_api_format": "claude:messages",
|
||||
"client_api_format": "openai:responses",
|
||||
"needs_conversion": true,
|
||||
"mapped_model": "claude-sonnet-4-5",
|
||||
@@ -934,7 +934,7 @@ fn claude_to_openai_responses_stream_rewriter_converts_tool_use_to_function_call
|
||||
#[test]
|
||||
fn gemini_to_openai_responses_stream_rewriter_converts_function_call_to_completed_event() {
|
||||
let report_context = json!({
|
||||
"provider_api_format": "gemini:cli",
|
||||
"provider_api_format": "gemini:generate_content",
|
||||
"client_api_format": "openai:responses",
|
||||
"needs_conversion": true,
|
||||
"mapped_model": "gemini-2.5-pro",
|
||||
@@ -961,7 +961,7 @@ fn gemini_to_openai_responses_stream_rewriter_converts_function_call_to_complete
|
||||
#[test]
|
||||
fn gemini_to_openai_responses_compact_stream_rewriter_converts_function_call_to_completed_event() {
|
||||
let report_context = json!({
|
||||
"provider_api_format": "gemini:cli",
|
||||
"provider_api_format": "gemini:generate_content",
|
||||
"client_api_format": "openai:responses:compact",
|
||||
"needs_conversion": true,
|
||||
"mapped_model": "gemini-2.5-pro",
|
||||
@@ -989,7 +989,7 @@ fn gemini_to_openai_responses_compact_stream_rewriter_converts_function_call_to_
|
||||
fn openai_chat_to_claude_chat_stream_rewriter_converts_via_standard_matrix() {
|
||||
let report_context = json!({
|
||||
"provider_api_format": "openai:chat",
|
||||
"client_api_format": "claude:chat",
|
||||
"client_api_format": "claude:messages",
|
||||
"needs_conversion": true,
|
||||
"mapped_model": "gpt-5",
|
||||
});
|
||||
@@ -1029,7 +1029,7 @@ fn openai_chat_to_claude_chat_stream_rewriter_injects_default_usage_when_finish_
|
||||
{
|
||||
let report_context = json!({
|
||||
"provider_api_format": "openai:chat",
|
||||
"client_api_format": "claude:chat",
|
||||
"client_api_format": "claude:messages",
|
||||
"needs_conversion": true,
|
||||
"mapped_model": "gpt-5.4",
|
||||
});
|
||||
@@ -1066,7 +1066,7 @@ fn openai_chat_to_claude_chat_stream_rewriter_injects_default_usage_when_finish_
|
||||
fn openai_chat_to_gemini_cli_stream_rewriter_converts_via_standard_matrix() {
|
||||
let report_context = json!({
|
||||
"provider_api_format": "openai:chat",
|
||||
"client_api_format": "gemini:cli",
|
||||
"client_api_format": "gemini:generate_content",
|
||||
"needs_conversion": true,
|
||||
"mapped_model": "gpt-5",
|
||||
});
|
||||
|
||||
@@ -94,8 +94,8 @@ fn build_kiro_claude_cli_sync_finalize_payload(body_bytes: Vec<u8>) -> GatewaySy
|
||||
trace_id: "trace-kiro-cli-sync-local-finalize-123".to_string(),
|
||||
report_kind: "claude_cli_sync_finalize".to_string(),
|
||||
report_context: Some(json!({
|
||||
"client_api_format": "claude:cli",
|
||||
"provider_api_format": "claude:cli",
|
||||
"client_api_format": "claude:messages",
|
||||
"provider_api_format": "claude:messages",
|
||||
"model": "claude-sonnet-4",
|
||||
"mapped_model": "claude-sonnet-4-upstream",
|
||||
"needs_conversion": false,
|
||||
@@ -332,7 +332,7 @@ fn converts_claude_chat_response_to_openai_chat_response() {
|
||||
}),
|
||||
&json!({
|
||||
"client_api_format": "openai:chat",
|
||||
"provider_api_format": "claude:chat",
|
||||
"provider_api_format": "claude:messages",
|
||||
"model": "gpt-5"
|
||||
}),
|
||||
)
|
||||
@@ -386,7 +386,7 @@ fn converts_claude_chat_tool_use_to_openai_chat_tool_calls() {
|
||||
}),
|
||||
&json!({
|
||||
"client_api_format": "openai:chat",
|
||||
"provider_api_format": "claude:chat",
|
||||
"provider_api_format": "claude:messages",
|
||||
"model": "gpt-5"
|
||||
}),
|
||||
)
|
||||
@@ -443,7 +443,7 @@ fn converts_claude_chat_thinking_block_to_openai_reasoning_content() {
|
||||
}),
|
||||
&json!({
|
||||
"client_api_format": "openai:chat",
|
||||
"provider_api_format": "claude:chat",
|
||||
"provider_api_format": "claude:messages",
|
||||
"model": "gpt-5"
|
||||
}),
|
||||
)
|
||||
@@ -478,7 +478,7 @@ fn converts_gemini_chat_response_to_openai_chat_response() {
|
||||
}),
|
||||
&json!({
|
||||
"client_api_format": "openai:chat",
|
||||
"provider_api_format": "gemini:chat",
|
||||
"provider_api_format": "gemini:generate_content",
|
||||
"model": "gpt-5"
|
||||
}),
|
||||
)
|
||||
@@ -532,7 +532,7 @@ fn converts_gemini_chat_function_call_to_openai_chat_tool_calls() {
|
||||
}),
|
||||
&json!({
|
||||
"client_api_format": "openai:chat",
|
||||
"provider_api_format": "gemini:chat",
|
||||
"provider_api_format": "gemini:generate_content",
|
||||
"model": "gpt-5"
|
||||
}),
|
||||
)
|
||||
@@ -594,7 +594,7 @@ fn converts_gemini_chat_thought_part_to_openai_reasoning_content() {
|
||||
}),
|
||||
&json!({
|
||||
"client_api_format": "openai:chat",
|
||||
"provider_api_format": "gemini:chat",
|
||||
"provider_api_format": "gemini:generate_content",
|
||||
"model": "gpt-5"
|
||||
}),
|
||||
)
|
||||
@@ -634,7 +634,7 @@ fn converts_gemini_chat_inline_data_to_openai_chat_image_part() {
|
||||
}),
|
||||
&json!({
|
||||
"client_api_format": "openai:chat",
|
||||
"provider_api_format": "gemini:chat",
|
||||
"provider_api_format": "gemini:generate_content",
|
||||
"model": "gpt-5"
|
||||
}),
|
||||
)
|
||||
@@ -805,7 +805,7 @@ fn converts_claude_cli_response_to_openai_responses_response() {
|
||||
}),
|
||||
&json!({
|
||||
"client_api_format": "openai:responses",
|
||||
"provider_api_format": "claude:cli",
|
||||
"provider_api_format": "claude:messages",
|
||||
"model": "gpt-5"
|
||||
}),
|
||||
)
|
||||
@@ -862,7 +862,7 @@ fn converts_claude_cli_tool_use_to_openai_responses_function_call() {
|
||||
}),
|
||||
&json!({
|
||||
"client_api_format": "openai:responses",
|
||||
"provider_api_format": "claude:cli",
|
||||
"provider_api_format": "claude:messages",
|
||||
"model": "gpt-5"
|
||||
}),
|
||||
)
|
||||
@@ -927,7 +927,7 @@ fn converts_gemini_cli_response_to_openai_responses_response() {
|
||||
}),
|
||||
&json!({
|
||||
"client_api_format": "openai:responses",
|
||||
"provider_api_format": "gemini:cli",
|
||||
"provider_api_format": "gemini:generate_content",
|
||||
"model": "gpt-5"
|
||||
}),
|
||||
)
|
||||
@@ -989,7 +989,7 @@ fn converts_gemini_cli_function_call_to_openai_responses_function_call() {
|
||||
}),
|
||||
&json!({
|
||||
"client_api_format": "openai:responses",
|
||||
"provider_api_format": "gemini:cli",
|
||||
"provider_api_format": "gemini:generate_content",
|
||||
"model": "gpt-5"
|
||||
}),
|
||||
)
|
||||
@@ -1062,7 +1062,7 @@ fn converts_gemini_cli_inline_data_to_openai_responses_output_image() {
|
||||
}),
|
||||
&json!({
|
||||
"client_api_format": "openai:responses",
|
||||
"provider_api_format": "gemini:cli",
|
||||
"provider_api_format": "gemini:generate_content",
|
||||
"model": "gpt-5"
|
||||
}),
|
||||
)
|
||||
@@ -1084,7 +1084,7 @@ fn local_finalize_handles_openai_responses_compact_cross_format_sync_response()
|
||||
report_kind: "openai_responses_compact_sync_finalize".to_string(),
|
||||
report_context: Some(json!({
|
||||
"client_api_format": "openai:responses:compact",
|
||||
"provider_api_format": "gemini:cli",
|
||||
"provider_api_format": "gemini:generate_content",
|
||||
"model": "gpt-5",
|
||||
"needs_conversion": true,
|
||||
"has_envelope": false,
|
||||
@@ -1140,7 +1140,7 @@ fn local_finalize_handles_openai_responses_compact_cross_format_function_call_re
|
||||
report_kind: "openai_responses_compact_sync_finalize".to_string(),
|
||||
report_context: Some(json!({
|
||||
"client_api_format": "openai:responses:compact",
|
||||
"provider_api_format": "gemini:cli",
|
||||
"provider_api_format": "gemini:generate_content",
|
||||
"model": "gpt-5",
|
||||
"needs_conversion": true,
|
||||
"has_envelope": false,
|
||||
@@ -1311,7 +1311,7 @@ fn local_finalize_handles_openai_responses_cross_format_stream_response_from_gem
|
||||
report_kind: "openai_responses_sync_finalize".to_string(),
|
||||
report_context: Some(json!({
|
||||
"client_api_format": "openai:responses",
|
||||
"provider_api_format": "gemini:cli",
|
||||
"provider_api_format": "gemini:generate_content",
|
||||
"model": "gpt-5",
|
||||
"mapped_model": "gemini-2.5-pro-upstream",
|
||||
"needs_conversion": true,
|
||||
@@ -1445,7 +1445,7 @@ fn local_finalize_handles_openai_chat_cross_format_sync_response_from_claude() {
|
||||
report_kind: "openai_chat_sync_finalize".to_string(),
|
||||
report_context: Some(json!({
|
||||
"client_api_format": "openai:chat",
|
||||
"provider_api_format": "claude:chat",
|
||||
"provider_api_format": "claude:messages",
|
||||
"model": "gpt-5",
|
||||
"mapped_model": "claude-sonnet-4",
|
||||
"needs_conversion": true,
|
||||
@@ -1501,7 +1501,7 @@ fn local_finalize_handles_openai_chat_cross_format_sync_response_from_gemini() {
|
||||
report_kind: "openai_chat_sync_finalize".to_string(),
|
||||
report_context: Some(json!({
|
||||
"client_api_format": "openai:chat",
|
||||
"provider_api_format": "gemini:chat",
|
||||
"provider_api_format": "gemini:generate_content",
|
||||
"model": "gpt-5",
|
||||
"mapped_model": "gemini-2.5-pro",
|
||||
"needs_conversion": true,
|
||||
@@ -1650,7 +1650,7 @@ fn local_finalize_handles_claude_chat_cross_format_sync_response_from_openai_cha
|
||||
trace_id: "trace-claude-chat-xfmt-openai-sync-123".to_string(),
|
||||
report_kind: "claude_chat_sync_finalize".to_string(),
|
||||
report_context: Some(json!({
|
||||
"client_api_format": "claude:chat",
|
||||
"client_api_format": "claude:messages",
|
||||
"provider_api_format": "openai:chat",
|
||||
"model": "claude-sonnet-4-5",
|
||||
"mapped_model": "gpt-5",
|
||||
@@ -1690,7 +1690,7 @@ fn local_finalize_handles_claude_chat_cross_format_sync_response_from_openai_cha
|
||||
route_class: Some("ai_public".to_string()),
|
||||
route_family: Some("claude".to_string()),
|
||||
route_kind: Some("chat".to_string()),
|
||||
auth_endpoint_signature: Some("claude:chat".to_string()),
|
||||
auth_endpoint_signature: Some("claude:messages".to_string()),
|
||||
execution_runtime_candidate: true,
|
||||
auth_context: None,
|
||||
admin_principal: None,
|
||||
@@ -1719,8 +1719,8 @@ fn local_finalize_handles_gemini_cli_cross_format_sync_response_from_claude_cli(
|
||||
trace_id: "trace-gemini-cli-xfmt-claude-sync-123".to_string(),
|
||||
report_kind: "gemini_cli_sync_finalize".to_string(),
|
||||
report_context: Some(json!({
|
||||
"client_api_format": "gemini:cli",
|
||||
"provider_api_format": "claude:cli",
|
||||
"client_api_format": "gemini:generate_content",
|
||||
"provider_api_format": "claude:messages",
|
||||
"model": "gemini-cli",
|
||||
"mapped_model": "claude-code",
|
||||
"needs_conversion": true,
|
||||
@@ -1756,7 +1756,7 @@ fn local_finalize_handles_gemini_cli_cross_format_sync_response_from_claude_cli(
|
||||
route_class: Some("ai_public".to_string()),
|
||||
route_family: Some("gemini".to_string()),
|
||||
route_kind: Some("cli".to_string()),
|
||||
auth_endpoint_signature: Some("gemini:cli".to_string()),
|
||||
auth_endpoint_signature: Some("gemini:generate_content".to_string()),
|
||||
execution_runtime_candidate: true,
|
||||
auth_context: None,
|
||||
admin_principal: None,
|
||||
|
||||
@@ -388,7 +388,7 @@ fn resolve_request_transport_unsupported_reason(
|
||||
}
|
||||
return match provider_api_format.as_str() {
|
||||
"openai:chat" => local_openai_chat_transport_unsupported_reason(transport),
|
||||
"gemini:chat" | "gemini:cli" => local_gemini_transport_unsupported_reason_with_network(
|
||||
"gemini:generate_content" => local_gemini_transport_unsupported_reason_with_network(
|
||||
transport,
|
||||
provider_api_format.as_str(),
|
||||
),
|
||||
@@ -472,7 +472,7 @@ mod tests {
|
||||
config: None,
|
||||
format_acceptance_config: Some(json!({
|
||||
"enabled": true,
|
||||
"accept_formats": ["claude:cli"]
|
||||
"accept_formats": ["claude:messages"]
|
||||
})),
|
||||
proxy: None,
|
||||
},
|
||||
@@ -519,7 +519,7 @@ mod tests {
|
||||
endpoint: GatewayProviderTransportEndpoint {
|
||||
id: "endpoint-cc-1".to_string(),
|
||||
provider_id: "provider-cc-1".to_string(),
|
||||
api_format: "claude:cli".to_string(),
|
||||
api_format: "claude:messages".to_string(),
|
||||
api_family: Some("claude".to_string()),
|
||||
endpoint_kind: Some("cli".to_string()),
|
||||
is_active: true,
|
||||
@@ -538,7 +538,7 @@ mod tests {
|
||||
name: "CC-特价-0.4".to_string(),
|
||||
auth_type: "api_key".to_string(),
|
||||
is_active: true,
|
||||
api_formats: Some(vec!["claude:cli".to_string()]),
|
||||
api_formats: Some(vec!["claude:messages".to_string()]),
|
||||
allowed_models: None,
|
||||
capabilities: None,
|
||||
rate_multipliers: None,
|
||||
@@ -558,7 +558,7 @@ mod tests {
|
||||
&sample_candidate(),
|
||||
Some(&sample_transport()),
|
||||
"openai:responses",
|
||||
"claude:cli",
|
||||
"claude:messages",
|
||||
serde_json::Map::new(),
|
||||
ExecutionStrategy::LocalCrossFormat,
|
||||
ConversionMode::Bidirectional,
|
||||
@@ -605,8 +605,8 @@ mod tests {
|
||||
let metadata = build_local_execution_candidate_metadata_for_candidate(
|
||||
&sample_candidate(),
|
||||
Some(&sample_claude_code_transport_without_auth()),
|
||||
"claude:cli",
|
||||
"claude:cli",
|
||||
"claude:messages",
|
||||
"claude:messages",
|
||||
serde_json::Map::new(),
|
||||
);
|
||||
|
||||
|
||||
@@ -151,7 +151,7 @@ fn planner_ranking_mode(mode: SchedulerSchedulingMode) -> SchedulerRankingMode {
|
||||
}
|
||||
|
||||
fn normalize_api_format_alias(value: &str) -> String {
|
||||
crate::ai_pipeline::normalize_legacy_openai_format_alias(value)
|
||||
crate::ai_pipeline::normalize_api_format_alias(value)
|
||||
}
|
||||
|
||||
fn api_format_matches(left: &str, right: &str) -> bool {
|
||||
@@ -564,7 +564,7 @@ mod tests {
|
||||
],
|
||||
vec![
|
||||
sample_endpoint_for_provider("provider-same", "endpoint-same", "openai:chat"),
|
||||
sample_endpoint_for_provider("provider-cross", "endpoint-cross", "claude:chat"),
|
||||
sample_endpoint_for_provider("provider-cross", "endpoint-cross", "claude:messages"),
|
||||
],
|
||||
vec![
|
||||
sample_key_for_provider("provider-same", "key-same", ""),
|
||||
@@ -586,7 +586,7 @@ mod tests {
|
||||
"provider-cross",
|
||||
"endpoint-cross",
|
||||
"key-cross",
|
||||
"claude:chat",
|
||||
"claude:messages",
|
||||
Some(0),
|
||||
0,
|
||||
),
|
||||
@@ -618,7 +618,7 @@ mod tests {
|
||||
],
|
||||
vec![
|
||||
sample_endpoint_for_provider("provider-same", "endpoint-same", "openai:chat"),
|
||||
sample_endpoint_for_provider("provider-cross", "endpoint-cross", "claude:chat"),
|
||||
sample_endpoint_for_provider("provider-cross", "endpoint-cross", "claude:messages"),
|
||||
],
|
||||
vec![
|
||||
sample_key_for_provider("provider-same", "key-same", ""),
|
||||
@@ -652,7 +652,7 @@ mod tests {
|
||||
"provider-cross",
|
||||
"endpoint-cross",
|
||||
"key-cross",
|
||||
"claude:chat",
|
||||
"claude:messages",
|
||||
Some(0),
|
||||
0,
|
||||
),
|
||||
@@ -675,7 +675,7 @@ mod tests {
|
||||
],
|
||||
vec![
|
||||
sample_endpoint_for_provider("provider-same", "endpoint-same", "openai:chat"),
|
||||
sample_endpoint_for_provider("provider-cross", "endpoint-cross", "claude:chat"),
|
||||
sample_endpoint_for_provider("provider-cross", "endpoint-cross", "claude:messages"),
|
||||
],
|
||||
vec![
|
||||
sample_key_for_provider("provider-same", "key-same", ""),
|
||||
@@ -697,7 +697,7 @@ mod tests {
|
||||
"provider-cross",
|
||||
"endpoint-cross",
|
||||
"key-cross",
|
||||
"claude:chat",
|
||||
"claude:messages",
|
||||
Some(0),
|
||||
0,
|
||||
),
|
||||
@@ -728,7 +728,7 @@ mod tests {
|
||||
],
|
||||
vec![
|
||||
sample_endpoint_for_provider("provider-same", "endpoint-same", "openai:chat"),
|
||||
sample_endpoint_for_provider("provider-cross", "endpoint-cross", "claude:chat"),
|
||||
sample_endpoint_for_provider("provider-cross", "endpoint-cross", "claude:messages"),
|
||||
],
|
||||
vec![
|
||||
sample_key_for_provider("provider-same", "key-same", ""),
|
||||
@@ -754,7 +754,7 @@ mod tests {
|
||||
"provider-cross",
|
||||
"endpoint-cross",
|
||||
"key-cross",
|
||||
"claude:chat",
|
||||
"claude:messages",
|
||||
Some(0),
|
||||
0,
|
||||
),
|
||||
@@ -846,7 +846,11 @@ mod tests {
|
||||
let provider_catalog = InMemoryProviderCatalogReadRepository::seed(
|
||||
vec![sample_provider_with_options("provider-shared", false, 0)],
|
||||
vec![
|
||||
sample_endpoint_for_provider("provider-shared", "aaa-claude-chat", "claude:chat"),
|
||||
sample_endpoint_for_provider(
|
||||
"provider-shared",
|
||||
"aaa-claude-chat",
|
||||
"claude:messages",
|
||||
),
|
||||
sample_endpoint_for_provider(
|
||||
"provider-shared",
|
||||
"zzz-openai-responses",
|
||||
@@ -858,7 +862,7 @@ mod tests {
|
||||
"key-shared",
|
||||
"",
|
||||
true,
|
||||
Some(json!(["claude:chat", "openai:responses"])),
|
||||
Some(json!(["claude:messages", "openai:responses"])),
|
||||
None,
|
||||
)],
|
||||
);
|
||||
@@ -877,7 +881,7 @@ mod tests {
|
||||
"provider-shared",
|
||||
"aaa-claude-chat",
|
||||
"key-shared",
|
||||
"claude:chat",
|
||||
"claude:messages",
|
||||
Some(0),
|
||||
0,
|
||||
),
|
||||
@@ -890,13 +894,13 @@ mod tests {
|
||||
0,
|
||||
),
|
||||
],
|
||||
"claude:cli",
|
||||
"claude:messages",
|
||||
None,
|
||||
)
|
||||
.await;
|
||||
|
||||
assert_eq!(ranked[0].endpoint_id, "zzz-openai-responses");
|
||||
assert_eq!(ranked[1].endpoint_id, "aaa-claude-chat");
|
||||
assert_eq!(ranked[0].endpoint_id, "aaa-claude-chat");
|
||||
assert_eq!(ranked[1].endpoint_id, "zzz-openai-responses");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -1117,7 +1121,7 @@ mod tests {
|
||||
sample_provider_with_options("provider-same", false, 10),
|
||||
],
|
||||
vec![
|
||||
sample_endpoint_for_provider("provider-cross", "endpoint-cross", "claude:chat"),
|
||||
sample_endpoint_for_provider("provider-cross", "endpoint-cross", "claude:messages"),
|
||||
sample_endpoint_for_provider("provider-same", "endpoint-same", "openai:chat"),
|
||||
],
|
||||
vec![
|
||||
@@ -1126,7 +1130,7 @@ mod tests {
|
||||
"key-cross",
|
||||
"",
|
||||
true,
|
||||
Some(json!(["claude:chat"])),
|
||||
Some(json!(["claude:messages"])),
|
||||
None,
|
||||
),
|
||||
sample_key_for_provider_with_options(
|
||||
@@ -1154,7 +1158,7 @@ mod tests {
|
||||
"provider-cross",
|
||||
"endpoint-cross",
|
||||
"key-cross",
|
||||
"claude:chat",
|
||||
"claude:messages",
|
||||
Some(0),
|
||||
0,
|
||||
),
|
||||
@@ -1188,14 +1192,18 @@ mod tests {
|
||||
vec![sample_provider_with_options("provider-shared", false, 0)],
|
||||
vec![
|
||||
sample_endpoint_for_provider("provider-shared", "endpoint-exact", "openai:chat"),
|
||||
sample_endpoint_for_provider("provider-shared", "endpoint-cross", "claude:chat"),
|
||||
sample_endpoint_for_provider(
|
||||
"provider-shared",
|
||||
"endpoint-cross",
|
||||
"claude:messages",
|
||||
),
|
||||
],
|
||||
vec![sample_key_for_provider_with_options(
|
||||
"provider-shared",
|
||||
"key-shared",
|
||||
"",
|
||||
true,
|
||||
Some(json!(["openai:chat", "claude:chat"])),
|
||||
Some(json!(["openai:chat", "claude:messages"])),
|
||||
None,
|
||||
)],
|
||||
);
|
||||
@@ -1222,7 +1230,7 @@ mod tests {
|
||||
"provider-shared",
|
||||
"endpoint-cross",
|
||||
"key-shared",
|
||||
"claude:chat",
|
||||
"claude:messages",
|
||||
Some(0),
|
||||
0,
|
||||
),
|
||||
@@ -1245,7 +1253,7 @@ mod tests {
|
||||
#[tokio::test]
|
||||
async fn realtime_gate_allows_cross_format_candidates_when_endpoint_acceptance_is_enabled() {
|
||||
let mut endpoint_cross =
|
||||
sample_endpoint_for_provider("provider-cross", "endpoint-cross", "claude:chat");
|
||||
sample_endpoint_for_provider("provider-cross", "endpoint-cross", "claude:messages");
|
||||
endpoint_cross.format_acceptance_config = Some(json!({
|
||||
"enabled": true,
|
||||
"accept_formats": ["openai:chat"],
|
||||
@@ -1266,7 +1274,7 @@ mod tests {
|
||||
"key-cross",
|
||||
"",
|
||||
true,
|
||||
Some(json!(["claude:chat"])),
|
||||
Some(json!(["claude:messages"])),
|
||||
None,
|
||||
),
|
||||
sample_key_for_provider_with_options(
|
||||
@@ -1294,7 +1302,7 @@ mod tests {
|
||||
"provider-cross",
|
||||
"endpoint-cross",
|
||||
"key-cross",
|
||||
"claude:chat",
|
||||
"claude:messages",
|
||||
Some(0),
|
||||
0,
|
||||
),
|
||||
|
||||
@@ -346,7 +346,7 @@ fn transport_key_supports_api_format(
|
||||
}
|
||||
|
||||
fn normalize_api_format_alias(value: &str) -> String {
|
||||
crate::ai_pipeline::normalize_legacy_openai_format_alias(value)
|
||||
crate::ai_pipeline::normalize_api_format_alias(value)
|
||||
}
|
||||
|
||||
fn api_format_matches(left: &str, right: &str) -> bool {
|
||||
|
||||
@@ -132,12 +132,15 @@ mod tests {
|
||||
use serde_json::json;
|
||||
|
||||
#[test]
|
||||
fn forces_streaming_for_codex_openai_responses_and_alias() {
|
||||
fn forces_streaming_for_codex_openai_responses() {
|
||||
assert!(force_upstream_streaming_for_provider(
|
||||
"codex",
|
||||
"openai:responses"
|
||||
));
|
||||
assert!(force_upstream_streaming_for_provider("codex", "openai:cli"));
|
||||
assert!(!force_upstream_streaming_for_provider(
|
||||
"codex",
|
||||
"openai:responses:compact"
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -148,11 +151,11 @@ mod tests {
|
||||
));
|
||||
assert!(!force_upstream_streaming_for_provider(
|
||||
"codex",
|
||||
"openai:compact"
|
||||
"openai:responses:compact"
|
||||
));
|
||||
assert!(!force_upstream_streaming_for_provider(
|
||||
"openai",
|
||||
"openai:cli"
|
||||
"openai:responses"
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
@@ -36,20 +36,15 @@ pub(crate) fn resolve_same_format_provider_transport_unsupported_reason_for_trac
|
||||
transport: &GatewayProviderTransportSnapshot,
|
||||
provider_api_format: &str,
|
||||
) -> Option<&'static str> {
|
||||
let provider_api_format = match crate::ai_pipeline::normalize_legacy_openai_format_alias(
|
||||
provider_api_format,
|
||||
)
|
||||
.as_str()
|
||||
{
|
||||
"openai:chat" => "openai:chat",
|
||||
"openai:responses" => "openai:responses",
|
||||
"openai:responses:compact" => "openai:responses:compact",
|
||||
"claude:chat" => "claude:chat",
|
||||
"claude:cli" => "claude:cli",
|
||||
"gemini:chat" => "gemini:chat",
|
||||
"gemini:cli" => "gemini:cli",
|
||||
_ => return Some("transport_api_format_unsupported"),
|
||||
};
|
||||
let provider_api_format =
|
||||
match crate::ai_pipeline::normalize_api_format_alias(provider_api_format).as_str() {
|
||||
"openai:chat" => "openai:chat",
|
||||
"openai:responses" => "openai:responses",
|
||||
"openai:responses:compact" => "openai:responses:compact",
|
||||
"claude:messages" => "claude:messages",
|
||||
"gemini:generate_content" => "gemini:generate_content",
|
||||
_ => return Some("transport_api_format_unsupported"),
|
||||
};
|
||||
let behavior = policy::classify_same_format_provider_request_behavior(
|
||||
transport,
|
||||
crate::ai_pipeline::planner::spec_metadata::LocalExecutionSurfaceSpecMetadata {
|
||||
|
||||
+3
-3
@@ -50,9 +50,9 @@ pub(super) fn classify_same_format_provider_request_behavior(
|
||||
let report_kind = if is_kiro && !spec_metadata.require_streaming {
|
||||
"claude_cli_sync_finalize"
|
||||
} else if is_antigravity && !spec_metadata.require_streaming {
|
||||
match spec_metadata.api_format {
|
||||
"gemini:chat" => "gemini_chat_sync_finalize",
|
||||
"gemini:cli" => "gemini_cli_sync_finalize",
|
||||
match default_report_kind {
|
||||
"gemini_chat_sync_success" => "gemini_chat_sync_finalize",
|
||||
"gemini_cli_sync_success" => "gemini_cli_sync_finalize",
|
||||
_ => default_report_kind,
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -32,7 +32,7 @@ use crate::{AppState, GatewayError};
|
||||
pub(super) use crate::ai_pipeline::planner::candidate_materialization::LocalExecutionCandidateAttempt as LocalGeminiFilesCandidateAttempt;
|
||||
pub(super) use crate::ai_pipeline::planner::decision_input::LocalAuthenticatedDecisionInput as LocalGeminiFilesDecisionInput;
|
||||
|
||||
pub(super) const GEMINI_FILES_CANDIDATE_API_FORMAT: &str = "gemini:chat";
|
||||
pub(super) const GEMINI_FILES_CANDIDATE_API_FORMAT: &str = "gemini:files";
|
||||
pub(super) const GEMINI_FILES_CLIENT_API_FORMAT: &str = "gemini:files";
|
||||
pub(super) const GEMINI_FILES_REQUIRED_CAPABILITY: &str = "gemini_files";
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ pub(crate) async fn resolve_local_standard_candidate_payload_parts(
|
||||
.provider_type
|
||||
.trim()
|
||||
.eq_ignore_ascii_case("kiro")
|
||||
&& provider_api_format.eq_ignore_ascii_case("claude:cli");
|
||||
&& provider_api_format.eq_ignore_ascii_case("claude:messages");
|
||||
let Some(conversion_kind) = crate::ai_pipeline::conversion::request_conversion_kind(
|
||||
spec_metadata.api_format,
|
||||
provider_api_format,
|
||||
|
||||
@@ -120,7 +120,7 @@ mod tests {
|
||||
|
||||
let converted = build_standard_request_body(
|
||||
&request,
|
||||
"claude:chat",
|
||||
"claude:messages",
|
||||
"gpt-5",
|
||||
"openai",
|
||||
"openai:chat",
|
||||
@@ -154,10 +154,10 @@ mod tests {
|
||||
|
||||
let converted = build_standard_request_body(
|
||||
&request,
|
||||
"gemini:chat",
|
||||
"gemini:generate_content",
|
||||
"claude-sonnet-4-5",
|
||||
"anthropic",
|
||||
"claude:chat",
|
||||
"claude:messages",
|
||||
"/v1beta/models/gemini-2.5-pro:generateContent",
|
||||
false,
|
||||
None,
|
||||
@@ -190,10 +190,10 @@ mod tests {
|
||||
|
||||
let converted = build_standard_request_body(
|
||||
&request,
|
||||
"claude:cli",
|
||||
"claude:messages",
|
||||
"gemini-2.5-pro",
|
||||
"google",
|
||||
"gemini:cli",
|
||||
"gemini:generate_content",
|
||||
"/v1/messages",
|
||||
false,
|
||||
None,
|
||||
@@ -223,7 +223,7 @@ mod tests {
|
||||
|
||||
let converted = build_standard_request_body(
|
||||
&request,
|
||||
"claude:cli",
|
||||
"claude:messages",
|
||||
"gpt-5",
|
||||
"openai",
|
||||
"openai:responses",
|
||||
@@ -258,7 +258,7 @@ mod tests {
|
||||
|
||||
let converted = build_standard_request_body(
|
||||
&request,
|
||||
"claude:cli",
|
||||
"claude:messages",
|
||||
"gpt-5",
|
||||
"codex",
|
||||
"openai:responses",
|
||||
|
||||
@@ -197,7 +197,7 @@ fn strips_metadata_for_codex_openai_responses_requests() {
|
||||
let provider_request_body = build_cross_format_openai_responses_request_body(
|
||||
&body_json,
|
||||
"gpt-5-upstream",
|
||||
"claude:cli",
|
||||
"claude:messages",
|
||||
"openai:responses",
|
||||
true,
|
||||
"codex",
|
||||
@@ -229,7 +229,7 @@ fn applies_codex_defaults_unless_body_rules_handle_the_field() {
|
||||
let provider_request_body = build_cross_format_openai_responses_request_body(
|
||||
&body_json,
|
||||
"gpt-5-upstream",
|
||||
"claude:cli",
|
||||
"claude:messages",
|
||||
"openai:responses",
|
||||
true,
|
||||
"codex",
|
||||
@@ -256,7 +256,7 @@ fn injects_codex_prompt_cache_key_for_openai_responses_cross_format_requests() {
|
||||
let provider_request_body = build_cross_format_openai_responses_request_body(
|
||||
&body_json,
|
||||
"gpt-5-upstream",
|
||||
"claude:cli",
|
||||
"claude:messages",
|
||||
"openai:responses",
|
||||
true,
|
||||
"codex",
|
||||
|
||||
+1
-1
@@ -265,7 +265,7 @@ pub(crate) async fn resolve_local_openai_chat_candidate_payload_parts(
|
||||
.provider_type
|
||||
.trim()
|
||||
.eq_ignore_ascii_case("kiro")
|
||||
&& provider_api_format.eq_ignore_ascii_case("claude:cli");
|
||||
&& provider_api_format.eq_ignore_ascii_case("claude:messages");
|
||||
let oauth_context = OauthPreparationContext {
|
||||
trace_id,
|
||||
api_format: provider_api_format.as_str(),
|
||||
|
||||
@@ -145,13 +145,13 @@ mod tests {
|
||||
"codex",
|
||||
"openai:responses"
|
||||
));
|
||||
assert!(openai_chat_sync_upstream_is_stream_for_candidate(
|
||||
assert!(!openai_chat_sync_upstream_is_stream_for_candidate(
|
||||
"codex",
|
||||
"openai:cli"
|
||||
"openai:responses:compact"
|
||||
));
|
||||
assert!(!openai_chat_sync_upstream_is_stream_for_candidate(
|
||||
"openai",
|
||||
"openai:cli"
|
||||
"openai:responses"
|
||||
));
|
||||
assert!(!openai_chat_sync_upstream_is_stream_for_candidate(
|
||||
"codex",
|
||||
|
||||
@@ -513,9 +513,9 @@ mod tests {
|
||||
provider_request_method: None,
|
||||
auth_header: Some("x-api-key".to_string()),
|
||||
auth_value: Some("sk-upstream-claude".to_string()),
|
||||
provider_api_format: Some("claude:chat".to_string()),
|
||||
provider_api_format: Some("claude:messages".to_string()),
|
||||
client_api_format: Some("openai:chat".to_string()),
|
||||
provider_contract: Some("claude:chat".to_string()),
|
||||
provider_contract: Some("claude:messages".to_string()),
|
||||
client_contract: Some("openai:chat".to_string()),
|
||||
model_name: Some("claude-sonnet-4-5".to_string()),
|
||||
mapped_model: Some("claude-sonnet-4-5".to_string()),
|
||||
|
||||
@@ -500,9 +500,9 @@ mod tests {
|
||||
provider_request_method: None,
|
||||
auth_header: Some("x-api-key".to_string()),
|
||||
auth_value: Some("sk-upstream-claude".to_string()),
|
||||
provider_api_format: Some("claude:chat".to_string()),
|
||||
provider_api_format: Some("claude:messages".to_string()),
|
||||
client_api_format: Some("openai:chat".to_string()),
|
||||
provider_contract: Some("claude:chat".to_string()),
|
||||
provider_contract: Some("claude:messages".to_string()),
|
||||
client_contract: Some("openai:chat".to_string()),
|
||||
model_name: Some("claude-sonnet-4-5".to_string()),
|
||||
mapped_model: Some("claude-sonnet-4-5".to_string()),
|
||||
|
||||
+6
-7
@@ -94,7 +94,7 @@ pub(crate) async fn resolve_local_openai_responses_candidate_payload_parts(
|
||||
.provider_type
|
||||
.trim()
|
||||
.eq_ignore_ascii_case("kiro")
|
||||
&& provider_api_format.eq_ignore_ascii_case("claude:cli");
|
||||
&& provider_api_format.eq_ignore_ascii_case("claude:messages");
|
||||
|
||||
let same_format = api_format_alias_matches(provider_api_format, &client_api_format);
|
||||
let conversion_kind = request_conversion_kind(spec_metadata.api_format, provider_api_format);
|
||||
@@ -104,7 +104,7 @@ pub(crate) async fn resolve_local_openai_responses_candidate_payload_parts(
|
||||
local_standard_transport_unsupported_reason_with_network(transport, provider_api_format)
|
||||
} else {
|
||||
match conversion_kind {
|
||||
Some(_) if is_antigravity && provider_api_format == "gemini:cli" => None,
|
||||
Some(_) if is_antigravity && provider_api_format == "gemini:generate_content" => None,
|
||||
Some(kind) => {
|
||||
crate::ai_pipeline::conversion::request_conversion_transport_unsupported_reason(
|
||||
transport, kind,
|
||||
@@ -162,10 +162,9 @@ pub(crate) async fn resolve_local_openai_responses_candidate_payload_parts(
|
||||
let direct_auth = if kiro_auth.is_some() {
|
||||
None
|
||||
} else if same_format {
|
||||
match crate::ai_pipeline::normalize_legacy_openai_format_alias(provider_api_format).as_str()
|
||||
{
|
||||
"gemini:cli" => resolve_local_gemini_auth(transport),
|
||||
"claude:cli" => resolve_local_standard_auth(transport),
|
||||
match crate::ai_pipeline::normalize_api_format_alias(provider_api_format).as_str() {
|
||||
"gemini:generate_content" => resolve_local_gemini_auth(transport),
|
||||
"claude:messages" => resolve_local_standard_auth(transport),
|
||||
"openai:responses" | "openai:responses:compact" => {
|
||||
resolve_local_openai_bearer_auth(transport)
|
||||
}
|
||||
@@ -536,7 +535,7 @@ pub(crate) async fn resolve_local_openai_responses_candidate_payload_parts(
|
||||
}
|
||||
|
||||
fn api_format_alias_matches(left: &str, right: &str) -> bool {
|
||||
crate::ai_pipeline::legacy_openai_format_alias_matches(left, right)
|
||||
crate::ai_pipeline::api_format_alias_matches(left, right)
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
|
||||
+1
-1
@@ -342,7 +342,7 @@ pub(crate) async fn materialize_local_openai_responses_candidate_attempts(
|
||||
}
|
||||
|
||||
fn api_format_alias_matches(left: &str, right: &str) -> bool {
|
||||
crate::ai_pipeline::legacy_openai_format_alias_matches(left, right)
|
||||
crate::ai_pipeline::api_format_alias_matches(left, right)
|
||||
}
|
||||
pub(crate) async fn mark_skipped_local_openai_responses_candidate(
|
||||
state: &AppState,
|
||||
|
||||
@@ -604,8 +604,9 @@ mod tests {
|
||||
}]
|
||||
});
|
||||
|
||||
let diagnostic = request_body_build_failure_extra_data(&body, "openai:chat", "claude:chat")
|
||||
.expect("diagnostic");
|
||||
let diagnostic =
|
||||
request_body_build_failure_extra_data(&body, "openai:chat", "claude:messages")
|
||||
.expect("diagnostic");
|
||||
|
||||
assert_eq!(
|
||||
diagnostic["request_body_build_error"]["path"],
|
||||
@@ -617,7 +618,7 @@ mod tests {
|
||||
);
|
||||
assert_eq!(
|
||||
diagnostic["failure_diagnostic"]["source"],
|
||||
"openai:chat_to_claude:chat"
|
||||
"openai:chat_to_claude:messages"
|
||||
);
|
||||
assert!(diagnostic["request_body_build_error"]["message"]
|
||||
.as_str()
|
||||
@@ -635,8 +636,9 @@ mod tests {
|
||||
}]
|
||||
});
|
||||
|
||||
let diagnostic = request_body_build_failure_extra_data(&body, "openai:chat", "claude:chat")
|
||||
.expect("diagnostic");
|
||||
let diagnostic =
|
||||
request_body_build_failure_extra_data(&body, "openai:chat", "claude:messages")
|
||||
.expect("diagnostic");
|
||||
|
||||
assert_eq!(
|
||||
diagnostic["request_body_build_error"]["path"],
|
||||
@@ -657,8 +659,9 @@ mod tests {
|
||||
}]
|
||||
});
|
||||
|
||||
let diagnostic = request_body_build_failure_extra_data(&body, "openai:chat", "gemini:chat")
|
||||
.expect("diagnostic");
|
||||
let diagnostic =
|
||||
request_body_build_failure_extra_data(&body, "openai:chat", "gemini:generate_content")
|
||||
.expect("diagnostic");
|
||||
|
||||
assert_eq!(
|
||||
diagnostic["request_body_build_error"]["path"],
|
||||
@@ -681,7 +684,7 @@ mod tests {
|
||||
});
|
||||
|
||||
let diagnostic =
|
||||
request_body_build_failure_extra_data(&body, "openai:responses", "claude:chat")
|
||||
request_body_build_failure_extra_data(&body, "openai:responses", "claude:messages")
|
||||
.expect("diagnostic");
|
||||
|
||||
assert_eq!(
|
||||
@@ -698,9 +701,12 @@ mod tests {
|
||||
"tool_choice": { "type": "function" }
|
||||
});
|
||||
|
||||
let diagnostic =
|
||||
request_body_build_failure_extra_data(&body, "openai:responses", "gemini:chat")
|
||||
.expect("diagnostic");
|
||||
let diagnostic = request_body_build_failure_extra_data(
|
||||
&body,
|
||||
"openai:responses",
|
||||
"gemini:generate_content",
|
||||
)
|
||||
.expect("diagnostic");
|
||||
|
||||
assert_eq!(
|
||||
diagnostic["request_body_build_error"]["path"],
|
||||
|
||||
@@ -2,7 +2,8 @@ pub(crate) use aether_ai_pipeline::api::{
|
||||
aggregate_claude_stream_sync_response, aggregate_gemini_stream_sync_response,
|
||||
aggregate_openai_chat_stream_sync_response, aggregate_openai_responses_stream_sync_response,
|
||||
aggregate_standard_chat_stream_sync_response, aggregate_standard_cli_stream_sync_response,
|
||||
apply_codex_openai_responses_special_body_edits, apply_codex_openai_responses_special_headers,
|
||||
api_format_alias_matches, apply_codex_openai_responses_special_body_edits,
|
||||
apply_codex_openai_responses_special_headers,
|
||||
apply_openai_responses_compact_special_body_edits, augment_sync_report_context,
|
||||
build_core_error_body_for_client_format, build_cross_format_openai_chat_request_body,
|
||||
build_cross_format_openai_responses_request_body, build_generated_tool_call_id,
|
||||
@@ -27,17 +28,17 @@ pub(crate) use aether_ai_pipeline::api::{
|
||||
force_upstream_streaming_for_provider, generic_decision_missing_exact_provider_request,
|
||||
implicit_sync_finalize_report_kind, is_core_error_finalize_kind, is_matching_stream_request,
|
||||
is_openai_responses_family_format, is_openai_responses_format, kiro_crc32,
|
||||
legacy_openai_format_alias_matches, map_claude_stop_reason,
|
||||
map_openai_reasoning_effort_to_claude_output, map_openai_reasoning_effort_to_gemini_budget,
|
||||
map_claude_stop_reason, map_openai_reasoning_effort_to_claude_output,
|
||||
map_openai_reasoning_effort_to_gemini_budget,
|
||||
maybe_build_openai_chat_cross_format_sync_product_from_normalized_payload,
|
||||
maybe_build_openai_responses_cross_format_sync_product_from_normalized_payload,
|
||||
maybe_build_openai_responses_same_family_sync_body_from_normalized_payload,
|
||||
maybe_build_standard_cross_format_sync_product,
|
||||
maybe_build_standard_cross_format_sync_product_from_normalized_payload,
|
||||
maybe_build_standard_same_format_sync_body_from_normalized_payload,
|
||||
maybe_build_standard_sync_finalize_product_from_normalized_payload,
|
||||
maybe_build_standard_sync_finalize_product_from_normalized_payload, normalize_api_format_alias,
|
||||
normalize_claude_request_to_openai_chat_request,
|
||||
normalize_gemini_request_to_openai_chat_request, normalize_legacy_openai_format_alias,
|
||||
normalize_gemini_request_to_openai_chat_request,
|
||||
normalize_openai_responses_request_to_openai_chat_request,
|
||||
normalize_provider_private_report_context, normalize_provider_private_response_value,
|
||||
normalize_standard_request_to_openai_chat_request, parse_direct_request_body,
|
||||
|
||||
Reference in New Issue
Block a user