Files
Aether/apps/aether-gateway/src/ai_serving/finalize/tests_sync.rs
T

2355 lines
85 KiB
Rust

use std::collections::BTreeMap;
use axum::body::to_bytes;
use base64::Engine as _;
use serde_json::json;
use super::{
aggregate_claude_stream_sync_response, aggregate_gemini_stream_sync_response,
aggregate_openai_chat_stream_sync_response, aggregate_openai_responses_stream_sync_response,
convert_claude_chat_response_to_openai_chat, convert_claude_response_to_openai_responses,
convert_gemini_chat_response_to_openai_chat, convert_gemini_response_to_openai_responses,
maybe_build_local_core_sync_finalize_response,
};
use crate::ai_serving::{
convert_openai_chat_response_to_openai_responses,
convert_openai_responses_response_to_openai_chat, openai_responses_message_item_id,
GatewayControlDecision,
};
use crate::usage::GatewaySyncReportRequest;
fn test_decision() -> GatewayControlDecision {
GatewayControlDecision {
public_path: "/v1/responses/compact".to_string(),
public_query_string: None,
route_class: Some("ai_public".to_string()),
route_family: Some("openai".to_string()),
route_kind: Some("compact".to_string()),
client_surface: None,
api_operation: None,
gateway_credential_carrier: None,
request_auth_channel: None,
auth_endpoint_signature: Some("openai:responses:compact".to_string()),
execution_runtime_candidate: true,
auth_context: None,
admin_principal: None,
local_auth_rejection: None,
model_directive_policy: Default::default(),
}
}
fn crc32(data: &[u8]) -> u32 {
let mut crc = 0xffff_ffffu32;
for &byte in data {
crc ^= byte as u32;
for _ in 0..8 {
let mask = if crc & 1 == 1 { 0xedb8_8320 } else { 0 };
crc = (crc >> 1) ^ mask;
}
}
!crc
}
fn encode_string_header(name: &str, value: &str) -> Vec<u8> {
let mut out = Vec::new();
out.push(name.len() as u8);
out.extend_from_slice(name.as_bytes());
out.push(7);
out.extend_from_slice(&(value.len() as u16).to_be_bytes());
out.extend_from_slice(value.as_bytes());
out
}
fn encode_frame(headers: Vec<u8>, payload: Vec<u8>) -> Vec<u8> {
let total_len = 12 + headers.len() + payload.len() + 4;
let header_len = headers.len();
let mut out = Vec::with_capacity(total_len);
out.extend_from_slice(&(total_len as u32).to_be_bytes());
out.extend_from_slice(&(header_len as u32).to_be_bytes());
let prelude_crc = crc32(&out[..8]);
out.extend_from_slice(&prelude_crc.to_be_bytes());
out.extend_from_slice(&headers);
out.extend_from_slice(&payload);
let message_crc = crc32(&out);
out.extend_from_slice(&message_crc.to_be_bytes());
out
}
fn encode_kiro_event_frame(event_type: &str, payload: serde_json::Value) -> Vec<u8> {
let mut headers = encode_string_header(":message-type", "event");
headers.extend_from_slice(&encode_string_header(":event-type", event_type));
let payload = serde_json::to_vec(&payload).expect("payload should encode");
encode_frame(headers, payload)
}
fn encode_kiro_exception_frame(exception_type: &str) -> Vec<u8> {
let mut headers = encode_string_header(":message-type", "exception");
headers.extend_from_slice(&encode_string_header(":exception-type", exception_type));
encode_frame(headers, Vec::new())
}
fn encode_kiro_error_frame(error_code: &str) -> Vec<u8> {
let mut headers = encode_string_header(":message-type", "error");
headers.extend_from_slice(&encode_string_header(":error-code", error_code));
encode_frame(headers, Vec::new())
}
fn build_kiro_claude_cli_sync_finalize_payload(body_bytes: Vec<u8>) -> GatewaySyncReportRequest {
GatewaySyncReportRequest {
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:messages",
"provider_api_format": "claude:messages",
"model": "claude-sonnet-4",
"mapped_model": "claude-sonnet-4-upstream",
"needs_conversion": false,
"has_envelope": true,
"envelope_name": "kiro:generateAssistantResponse",
"original_request_body": {
"model": "claude-sonnet-4",
"messages": []
}
})),
status_code: 200,
headers: BTreeMap::from([(
"content-type".to_string(),
"application/vnd.amazon.eventstream".to_string(),
)]),
body_json: None,
client_body_json: None,
body_base64: Some(base64::engine::general_purpose::STANDARD.encode(body_bytes)),
telemetry: None,
}
}
#[test]
fn aggregates_openai_chat_stream_text_chunks_to_final_response() {
let body = concat!(
"data: {\"id\":\"chatcmpl_123\",\"object\":\"chat.completion.chunk\",\"created\":1,",
"\"model\":\"gpt-5\",\"choices\":[{\"index\":0,\"delta\":{\"role\":\"assistant\",\"content\":\"Hel\"},\"finish_reason\":null}]}\n\n",
"data: {\"id\":\"chatcmpl_123\",\"object\":\"chat.completion.chunk\",\"model\":\"gpt-5\",",
"\"choices\":[{\"index\":0,\"delta\":{\"content\":\"lo\"},\"finish_reason\":null}]}\n\n",
"data: {\"id\":\"chatcmpl_123\",\"object\":\"chat.completion.chunk\",\"model\":\"gpt-5\",",
"\"choices\":[{\"index\":0,\"delta\":{},\"finish_reason\":\"stop\"}],",
"\"usage\":{\"prompt_tokens\":1,\"completion_tokens\":2,\"total_tokens\":3}}\n\n",
"data: [DONE]\n\n",
);
let result =
aggregate_openai_chat_stream_sync_response(body.as_bytes()).expect("result should exist");
assert_eq!(
result,
json!({
"id": "chatcmpl_123",
"object": "chat.completion",
"created": 1,
"model": "gpt-5",
"choices": [{
"index": 0,
"message": {
"role": "assistant",
"content": "Hello",
},
"finish_reason": "stop",
}],
"usage": {
"prompt_tokens": 1,
"completion_tokens": 2,
"total_tokens": 3,
},
})
);
}
#[test]
fn aggregates_openai_responses_stream_completed_event_to_final_response() {
let body = concat!(
"event: response.created\n",
"data: {\"type\":\"response.created\",\"response\":{\"id\":\"resp_123\",\"object\":\"response\",\"model\":\"gpt-5\",\"status\":\"in_progress\",\"output\":[]}}\n\n",
"event: response.output_text.delta\n",
"data: {\"type\":\"response.output_text.delta\",\"output_index\":0,\"content_index\":0,\"delta\":\"Hello\"}\n\n",
"event: response.completed\n",
"data: {\"type\":\"response.completed\",\"response\":{\"id\":\"resp_123\",\"object\":\"response\",\"model\":\"gpt-5\",\"status\":\"completed\",\"output\":[],\"usage\":{\"input_tokens\":1,\"output_tokens\":2,\"total_tokens\":3}}}\n\n",
);
let result = aggregate_openai_responses_stream_sync_response(body.as_bytes())
.expect("result should exist");
let created_at = result["created_at"]
.as_i64()
.expect("created_at should be a unix timestamp");
assert_eq!(
result,
json!({
"id": "resp_123",
"object": "response",
"model": "gpt-5",
"status": "completed",
"created_at": created_at,
"completed_at": created_at,
"output_text": "Hello",
"output": [{
"type": "message",
"id": openai_responses_message_item_id("resp_123", 0),
"role": "assistant",
"status": "completed",
"content": [{
"type": "output_text",
"text": "Hello",
"annotations": []
}]
}],
"usage": {
"input_tokens": 1,
"output_tokens": 2,
"total_tokens": 3,
},
})
);
}
#[test]
fn aggregates_openai_responses_stream_tool_call_events_to_final_response() {
let body = concat!(
"event: response.created\n",
"data: {\"type\":\"response.created\",\"response\":{\"id\":\"resp_tool_123\",\"object\":\"response\",\"model\":\"gpt-5\",\"status\":\"in_progress\",\"output\":[]}}\n\n",
"event: response.output_item.added\n",
"data: {\"type\":\"response.output_item.added\",\"output_index\":1,\"item\":{\"type\":\"function_call\",\"id\":\"call_123\",\"call_id\":\"call_123\",\"name\":\"get_weather\",\"arguments\":\"\",\"status\":\"in_progress\"}}\n\n",
"event: response.function_call_arguments.delta\n",
"data: {\"type\":\"response.function_call_arguments.delta\",\"output_index\":1,\"item_id\":\"call_123\",\"call_id\":\"call_123\",\"delta\":\"{\\\"city\\\":\\\"SF\\\"}\"}\n\n",
"event: response.completed\n",
"data: {\"type\":\"response.completed\",\"response\":{\"id\":\"resp_tool_123\",\"object\":\"response\",\"model\":\"gpt-5\",\"status\":\"completed\",\"output\":[],\"usage\":{\"input_tokens\":1,\"output_tokens\":2,\"total_tokens\":3}}}\n\n",
);
let result = aggregate_openai_responses_stream_sync_response(body.as_bytes())
.expect("result should exist");
let created_at = result["created_at"]
.as_i64()
.expect("created_at should be a unix timestamp");
assert_eq!(
result,
json!({
"id": "resp_tool_123",
"object": "response",
"model": "gpt-5",
"status": "completed",
"created_at": created_at,
"completed_at": created_at,
"output_text": "",
"output": [{
"type": "function_call",
"id": "call_123",
"call_id": "call_123",
"name": "get_weather",
"arguments": "{\"city\":\"SF\"}",
"status": "in_progress",
}],
"usage": {
"input_tokens": 1,
"output_tokens": 2,
"total_tokens": 3,
},
})
);
}
#[test]
fn aggregates_claude_stream_events_to_final_response() {
let body = concat!(
"event: message_start\n",
"data: {\"type\":\"message_start\",\"message\":{\"id\":\"msg_1\",\"type\":\"message\",\"role\":\"assistant\",\"model\":\"claude-3-5-sonnet-latest\",\"content\":[],\"stop_reason\":null,\"stop_sequence\":null}}\n\n",
"event: content_block_start\n",
"data: {\"type\":\"content_block_start\",\"index\":0,\"content_block\":{\"type\":\"text\",\"text\":\"\"}}\n\n",
"event: content_block_delta\n",
"data: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"text_delta\",\"text\":\"hello\"}}\n\n",
"event: content_block_stop\n",
"data: {\"type\":\"content_block_stop\",\"index\":0}\n\n",
"event: message_delta\n",
"data: {\"type\":\"message_delta\",\"delta\":{\"stop_reason\":\"end_turn\"},\"usage\":{\"input_tokens\":5,\"output_tokens\":7}}\n\n",
"event: message_stop\n",
"data: {\"type\":\"message_stop\"}\n\n",
);
let result =
aggregate_claude_stream_sync_response(body.as_bytes()).expect("result should exist");
assert_eq!(
result,
json!({
"id": "msg_1",
"type": "message",
"role": "assistant",
"model": "claude-3-5-sonnet-latest",
"content": [{
"type": "text",
"text": "hello"
}],
"stop_reason": "end_turn",
"stop_sequence": null,
"usage": {
"input_tokens": 5,
"output_tokens": 7
}
})
);
}
#[test]
fn aggregates_gemini_stream_events_to_final_response() {
let body = concat!(
"data: {\"responseId\":\"resp_gemini_123\",\"candidates\":[{\"content\":{\"parts\":[{\"text\":\"he\"}],\"role\":\"model\"},\"index\":0}],\"modelVersion\":\"gemini-1.5-flash\"}\n\n",
"data: {\"responseId\":\"resp_gemini_123\",\"candidates\":[{\"content\":{\"parts\":[{\"text\":\"hello\"}],\"role\":\"model\"},\"finishReason\":\"STOP\",\"index\":0}],\"modelVersion\":\"gemini-1.5-flash\",\"usageMetadata\":{\"promptTokenCount\":5,\"candidatesTokenCount\":7,\"totalTokenCount\":12}}\n\n",
);
let result =
aggregate_gemini_stream_sync_response(body.as_bytes()).expect("result should exist");
assert_eq!(
result,
json!({
"responseId": "resp_gemini_123",
"candidates": [{
"content": {
"parts": [{"text": "hello"}],
"role": "model"
},
"finishReason": "STOP",
"index": 0
}],
"modelVersion": "gemini-1.5-flash",
"usageMetadata": {
"promptTokenCount": 5,
"candidatesTokenCount": 7,
"totalTokenCount": 12
}
})
);
}
#[test]
fn converts_claude_chat_response_to_openai_chat_response() {
let result = convert_claude_chat_response_to_openai_chat(
&json!({
"id": "msg_123",
"type": "message",
"role": "assistant",
"model": "claude-sonnet-4-upstream",
"content": [
{"type": "text", "text": "Hello"},
{"type": "text", "text": " Claude"}
],
"stop_reason": "end_turn",
"usage": {
"input_tokens": 5,
"output_tokens": 7
}
}),
&json!({
"client_api_format": "openai:chat",
"provider_api_format": "claude:messages",
"model": "gpt-5"
}),
)
.expect("result should exist");
assert_eq!(
result,
json!({
"id": "msg_123",
"object": "chat.completion",
"model": "claude-sonnet-4-upstream",
"choices": [{
"index": 0,
"message": {
"role": "assistant",
"content": "Hello Claude"
},
"finish_reason": "stop"
}],
"usage": {
"prompt_tokens": 5,
"completion_tokens": 7,
"total_tokens": 12
}
})
);
}
#[test]
fn converts_claude_chat_tool_use_to_openai_chat_tool_calls() {
let result = convert_claude_chat_response_to_openai_chat(
&json!({
"id": "msg_tool_123",
"type": "message",
"role": "assistant",
"model": "claude-sonnet-4-upstream",
"content": [
{"type": "text", "text": "Checking."},
{
"type": "tool_use",
"id": "toolu_123",
"name": "get_weather",
"input": {"location": "Tokyo"}
}
],
"stop_reason": "tool_use",
"usage": {
"input_tokens": 5,
"output_tokens": 7
}
}),
&json!({
"client_api_format": "openai:chat",
"provider_api_format": "claude:messages",
"model": "gpt-5"
}),
)
.expect("result should exist");
assert_eq!(
result,
json!({
"id": "msg_tool_123",
"object": "chat.completion",
"model": "claude-sonnet-4-upstream",
"choices": [{
"index": 0,
"message": {
"role": "assistant",
"content": "Checking.",
"tool_calls": [{
"id": "toolu_123",
"type": "function",
"function": {
"name": "get_weather",
"arguments": "{\"location\":\"Tokyo\"}"
}
}]
},
"finish_reason": "tool_calls"
}],
"usage": {
"prompt_tokens": 5,
"completion_tokens": 7,
"total_tokens": 12
}
})
);
}
#[test]
fn converts_claude_chat_thinking_block_to_openai_reasoning_content() {
let result = convert_claude_chat_response_to_openai_chat(
&json!({
"id": "msg_think_123",
"type": "message",
"role": "assistant",
"model": "claude-sonnet-4-upstream",
"content": [
{"type": "thinking", "thinking": "Need to reason first."},
{"type": "text", "text": "Final answer"}
],
"stop_reason": "end_turn",
"usage": {
"input_tokens": 5,
"output_tokens": 7
}
}),
&json!({
"client_api_format": "openai:chat",
"provider_api_format": "claude:messages",
"model": "gpt-5"
}),
)
.expect("result should exist");
assert_eq!(
result["choices"][0]["message"]["reasoning_content"],
"Need to reason first."
);
assert_eq!(result["choices"][0]["message"]["content"], "Final answer");
}
#[test]
fn converts_gemini_chat_response_to_openai_chat_response() {
let result = convert_gemini_chat_response_to_openai_chat(
&json!({
"responseId": "resp_123",
"candidates": [{
"content": {
"parts": [{"text": "Hello Gemini"}],
"role": "model"
},
"finishReason": "STOP",
"index": 0
}],
"modelVersion": "gemini-2.5-pro-upstream",
"usageMetadata": {
"promptTokenCount": 1,
"candidatesTokenCount": 2,
"totalTokenCount": 3
}
}),
&json!({
"client_api_format": "openai:chat",
"provider_api_format": "gemini:generate_content",
"model": "gpt-5"
}),
)
.expect("result should exist");
assert_eq!(
result,
json!({
"id": "resp_123",
"object": "chat.completion",
"model": "gemini-2.5-pro-upstream",
"choices": [{
"index": 0,
"message": {
"role": "assistant",
"content": "Hello Gemini"
},
"finish_reason": "stop"
}],
"usage": {
"prompt_tokens": 1,
"completion_tokens": 2,
"total_tokens": 3
}
})
);
}
#[test]
fn converts_gemini_chat_function_call_to_openai_chat_tool_calls() {
let result = convert_gemini_chat_response_to_openai_chat(
&json!({
"responseId": "resp_tool_123",
"candidates": [{
"content": {
"parts": [
{"text": "Let me call a tool."},
{"functionCall": {"name": "get_weather", "args": {"city": "SF"}}}
],
"role": "model"
},
"finishReason": "STOP",
"index": 0
}],
"modelVersion": "gemini-2.5-pro-upstream",
"usageMetadata": {
"promptTokenCount": 1,
"candidatesTokenCount": 2,
"totalTokenCount": 3
}
}),
&json!({
"client_api_format": "openai:chat",
"provider_api_format": "gemini:generate_content",
"model": "gpt-5"
}),
)
.expect("result should exist");
assert_eq!(
result,
json!({
"id": "resp_tool_123",
"object": "chat.completion",
"model": "gemini-2.5-pro-upstream",
"choices": [{
"index": 0,
"message": {
"role": "assistant",
"content": "Let me call a tool.",
"tool_calls": [{
"id": "call_auto_1",
"type": "function",
"function": {
"name": "get_weather",
"arguments": "{\"city\":\"SF\"}"
}
}]
},
"finish_reason": "tool_calls"
}],
"usage": {
"prompt_tokens": 1,
"completion_tokens": 2,
"total_tokens": 3
}
})
);
}
#[test]
fn converts_gemini_chat_thought_part_to_openai_reasoning_content() {
let result = convert_gemini_chat_response_to_openai_chat(
&json!({
"responseId": "resp_think_123",
"candidates": [{
"content": {
"parts": [
{"text": "Internal reasoning.", "thought": true},
{"text": "Visible answer"}
],
"role": "model"
},
"finishReason": "STOP",
"index": 0
}],
"modelVersion": "gemini-2.5-pro-upstream",
"usageMetadata": {
"promptTokenCount": 1,
"candidatesTokenCount": 2,
"totalTokenCount": 3
}
}),
&json!({
"client_api_format": "openai:chat",
"provider_api_format": "gemini:generate_content",
"model": "gpt-5"
}),
)
.expect("result should exist");
assert_eq!(
result["choices"][0]["message"]["reasoning_content"],
"Internal reasoning."
);
assert_eq!(result["choices"][0]["message"]["content"], "Visible answer");
}
#[test]
fn converts_gemini_chat_inline_data_to_openai_chat_image_part() {
let result = convert_gemini_chat_response_to_openai_chat(
&json!({
"responseId": "resp_img_123",
"candidates": [{
"content": {
"parts": [{
"inlineData": {
"mimeType": "image/png",
"data": "iVBORw0KGgo="
}
}],
"role": "model"
},
"finishReason": "STOP",
"index": 0
}],
"modelVersion": "gemini-2.5-pro-upstream",
"usageMetadata": {
"promptTokenCount": 1,
"candidatesTokenCount": 2,
"totalTokenCount": 3
}
}),
&json!({
"client_api_format": "openai:chat",
"provider_api_format": "gemini:generate_content",
"model": "gpt-5"
}),
)
.expect("result should exist");
assert_eq!(
result["choices"][0]["message"]["content"],
json!([{
"type": "image_url",
"image_url": {
"url": "data:image/png;base64,iVBORw0KGgo="
}
}])
);
}
#[test]
fn converts_openai_responses_reasoning_item_to_openai_chat_reasoning_content() {
let result = convert_openai_responses_response_to_openai_chat(
&json!({
"id": "resp_reason_123",
"object": "response",
"model": "gpt-5",
"output": [
{
"type": "reasoning",
"id": "rs_1",
"summary": [{
"type": "summary_text",
"text": "Thinking summary."
}]
},
{
"type": "message",
"id": "msg_1",
"role": "assistant",
"status": "completed",
"content": [{
"type": "output_text",
"text": "Final answer",
"annotations": []
}]
}
],
"usage": {
"input_tokens": 3,
"output_tokens": 5,
"total_tokens": 8
}
}),
&json!({
"client_api_format": "openai:chat",
"provider_api_format": "openai:responses",
"model": "gpt-5"
}),
)
.expect("result should exist");
assert_eq!(
result["choices"][0]["message"]["reasoning_content"],
"Thinking summary."
);
assert_eq!(result["choices"][0]["message"]["content"], "Final answer");
}
#[test]
fn converts_openai_responses_output_image_to_openai_chat_image_part() {
let result = convert_openai_responses_response_to_openai_chat(
&json!({
"id": "resp_img_cli_123",
"object": "response",
"model": "gpt-5",
"output": [{
"type": "message",
"id": "msg_1",
"role": "assistant",
"status": "completed",
"content": [{
"type": "output_image",
"image_url": "data:image/png;base64,iVBORw0KGgo="
}]
}],
"usage": {
"input_tokens": 3,
"output_tokens": 5,
"total_tokens": 8
}
}),
&json!({
"client_api_format": "openai:chat",
"provider_api_format": "openai:responses",
"model": "gpt-5"
}),
)
.expect("result should exist");
assert_eq!(
result["choices"][0]["message"]["content"],
json!([{
"type": "image_url",
"image_url": {
"url": "data:image/png;base64,iVBORw0KGgo="
}
}])
);
}
#[test]
fn converts_openai_chat_image_part_to_openai_responses_output_image() {
let result = convert_openai_chat_response_to_openai_responses(
&json!({
"id": "chatcmpl_img_123",
"object": "chat.completion",
"model": "gpt-5",
"choices": [{
"index": 0,
"message": {
"role": "assistant",
"content": [{
"type": "image_url",
"image_url": {
"url": "data:image/png;base64,iVBORw0KGgo="
}
}]
},
"finish_reason": "stop"
}],
"usage": {
"prompt_tokens": 3,
"completion_tokens": 5,
"total_tokens": 8
}
}),
&json!({
"client_api_format": "openai:responses",
"provider_api_format": "openai:chat",
"model": "gpt-5"
}),
false,
)
.expect("result should exist");
assert_eq!(
result["output"][0]["content"],
json!([{
"type": "output_image",
"image_url": "data:image/png;base64,iVBORw0KGgo="
}])
);
}
#[test]
fn converts_claude_cli_response_to_openai_responses_response() {
let result = convert_claude_response_to_openai_responses(
&json!({
"id": "msg_cli_123",
"type": "message",
"role": "assistant",
"model": "claude-code-upstream",
"content": [
{"type": "text", "text": "Hello"},
{"type": "text", "text": " Claude CLI"}
],
"usage": {
"input_tokens": 4,
"output_tokens": 6
}
}),
&json!({
"client_api_format": "openai:responses",
"provider_api_format": "claude:messages",
"model": "gpt-5"
}),
)
.expect("result should exist");
let created_at = result["created_at"]
.as_i64()
.expect("created_at should be a unix timestamp");
assert_eq!(
result,
json!({
"id": "msg_cli_123",
"object": "response",
"status": "completed",
"model": "claude-code-upstream",
"created_at": created_at,
"completed_at": created_at,
"output_text": "Hello Claude CLI",
"output": [{
"type": "message",
"id": openai_responses_message_item_id("msg_cli_123", 0),
"role": "assistant",
"status": "completed",
"content": [{
"type": "output_text",
"text": "Hello Claude CLI",
"annotations": []
}]
}],
"usage": {
"input_tokens": 4,
"output_tokens": 6,
"total_tokens": 10
}
})
);
}
#[test]
fn converts_claude_cli_tool_use_to_openai_responses_function_call() {
let result = convert_claude_response_to_openai_responses(
&json!({
"id": "msg_cli_tool_123",
"type": "message",
"role": "assistant",
"model": "claude-code-upstream",
"content": [
{"type": "text", "text": "Running tool."},
{
"type": "tool_use",
"id": "tool_123",
"name": "read_file",
"input": {"path": "/tmp/test.txt"}
}
],
"usage": {
"input_tokens": 4,
"output_tokens": 6
}
}),
&json!({
"client_api_format": "openai:responses",
"provider_api_format": "claude:messages",
"model": "gpt-5"
}),
)
.expect("result should exist");
let created_at = result["created_at"]
.as_i64()
.expect("created_at should be a unix timestamp");
assert_eq!(
result,
json!({
"id": "msg_cli_tool_123",
"object": "response",
"status": "completed",
"model": "claude-code-upstream",
"created_at": created_at,
"completed_at": created_at,
"output_text": "Running tool.",
"output": [
{
"type": "message",
"id": openai_responses_message_item_id("msg_cli_tool_123", 0),
"role": "assistant",
"status": "completed",
"content": [{
"type": "output_text",
"text": "Running tool.",
"annotations": []
}]
},
{
"type": "function_call",
"id": "tool_123",
"call_id": "tool_123",
"name": "read_file",
"arguments": "{\"path\":\"/tmp/test.txt\"}"
}
],
"usage": {
"input_tokens": 4,
"output_tokens": 6,
"total_tokens": 10
}
})
);
}
#[test]
fn converts_gemini_cli_response_to_openai_responses_response() {
let result = convert_gemini_response_to_openai_responses(
&json!({
"responseId": "resp_cli_123",
"candidates": [{
"content": {
"parts": [{"text": "Hello Gemini CLI"}],
"role": "model"
},
"finishReason": "STOP",
"index": 0
}],
"modelVersion": "gemini-cli-upstream",
"usageMetadata": {
"promptTokenCount": 3,
"candidatesTokenCount": 5,
"thoughtsTokenCount": 2,
"totalTokenCount": 10
}
}),
&json!({
"client_api_format": "openai:responses",
"provider_api_format": "gemini:generate_content",
"model": "gpt-5"
}),
)
.expect("result should exist");
let created_at = result["created_at"]
.as_i64()
.expect("created_at should be a unix timestamp");
assert_eq!(
result,
json!({
"id": "resp_cli_123",
"object": "response",
"status": "completed",
"model": "gemini-cli-upstream",
"created_at": created_at,
"completed_at": created_at,
"output_text": "Hello Gemini CLI",
"output": [{
"type": "message",
"id": openai_responses_message_item_id("resp_cli_123", 0),
"role": "assistant",
"status": "completed",
"content": [{
"type": "output_text",
"text": "Hello Gemini CLI",
"annotations": []
}]
}],
"usage": {
"input_tokens": 3,
"output_tokens": 7,
"total_tokens": 10,
"output_tokens_details": {
"reasoning_tokens": 2
}
}
})
);
}
#[test]
fn converts_gemini_cli_function_call_to_openai_responses_function_call() {
let result = convert_gemini_response_to_openai_responses(
&json!({
"responseId": "resp_cli_tool_123",
"candidates": [{
"content": {
"parts": [
{"text": "Need a tool."},
{"functionCall": {"name": "get_weather", "args": {"location": "Tokyo"}}}
],
"role": "model"
},
"finishReason": "STOP",
"index": 0
}],
"modelVersion": "gemini-cli-upstream",
"usageMetadata": {
"promptTokenCount": 3,
"candidatesTokenCount": 5,
"thoughtsTokenCount": 2,
"totalTokenCount": 10
}
}),
&json!({
"client_api_format": "openai:responses",
"provider_api_format": "gemini:generate_content",
"model": "gpt-5"
}),
)
.expect("result should exist");
let created_at = result["created_at"]
.as_i64()
.expect("created_at should be a unix timestamp");
assert_eq!(
result,
json!({
"id": "resp_cli_tool_123",
"object": "response",
"status": "completed",
"model": "gemini-cli-upstream",
"created_at": created_at,
"completed_at": created_at,
"output_text": "Need a tool.",
"output": [
{
"type": "message",
"id": openai_responses_message_item_id("resp_cli_tool_123", 0),
"role": "assistant",
"status": "completed",
"content": [{
"type": "output_text",
"text": "Need a tool.",
"annotations": []
}]
},
{
"type": "function_call",
"id": "call_auto_1",
"call_id": "call_auto_1",
"name": "get_weather",
"arguments": "{\"location\":\"Tokyo\"}"
}
],
"usage": {
"input_tokens": 3,
"output_tokens": 7,
"total_tokens": 10,
"output_tokens_details": {
"reasoning_tokens": 2
}
}
})
);
}
#[test]
fn converts_gemini_cli_inline_data_to_openai_responses_output_image() {
let result = convert_gemini_response_to_openai_responses(
&json!({
"responseId": "resp_cli_img_123",
"candidates": [{
"content": {
"parts": [{
"inlineData": {
"mimeType": "image/png",
"data": "iVBORw0KGgo="
}
}],
"role": "model"
},
"finishReason": "STOP",
"index": 0
}],
"modelVersion": "gemini-cli-upstream",
"usageMetadata": {
"promptTokenCount": 3,
"candidatesTokenCount": 5,
"thoughtsTokenCount": 2,
"totalTokenCount": 10
}
}),
&json!({
"client_api_format": "openai:responses",
"provider_api_format": "gemini:generate_content",
"model": "gpt-5"
}),
)
.expect("result should exist");
assert_eq!(
result["output"][0]["content"],
json!([{
"type": "output_image",
"image_url": "data:image/png;base64,iVBORw0KGgo="
}])
);
}
#[test]
fn local_finalize_handles_openai_responses_compact_cross_format_sync_response() {
let payload = GatewaySyncReportRequest {
trace_id: "trace-compact-sync-123".to_string(),
report_kind: "openai_responses_compact_sync_finalize".to_string(),
report_context: Some(json!({
"client_api_format": "openai:responses:compact",
"provider_api_format": "gemini:generate_content",
"model": "gpt-5",
"needs_conversion": true,
"has_envelope": false,
})),
status_code: 200,
headers: BTreeMap::from([("content-type".to_string(), "application/json".to_string())]),
body_json: Some(json!({
"responseId": "resp_cli_123",
"candidates": [{
"content": {
"parts": [{"text": "Hello Gemini CLI"}],
"role": "model"
},
"finishReason": "STOP",
"index": 0
}],
"modelVersion": "gemini-cli-upstream",
"usageMetadata": {
"promptTokenCount": 3,
"candidatesTokenCount": 5,
"thoughtsTokenCount": 2,
"totalTokenCount": 10
}
})),
client_body_json: None,
body_base64: None,
telemetry: None,
};
let outcome = maybe_build_local_core_sync_finalize_response(
"trace-compact-sync-123",
&test_decision(),
&payload,
)
.expect("local finalize should succeed")
.expect("local finalize should match");
assert_eq!(outcome.response.status(), 200);
let report = outcome
.background_report
.expect("compact cross-format should downgrade to success report");
assert_eq!(report.report_kind, "openai_responses_compact_sync_success");
assert_eq!(
report.client_body_json.expect("client body should exist")["object"],
"response.compaction"
);
}
#[test]
fn local_finalize_handles_openai_responses_compact_cross_format_function_call_response() {
let payload = GatewaySyncReportRequest {
trace_id: "trace-compact-tool-123".to_string(),
report_kind: "openai_responses_compact_sync_finalize".to_string(),
report_context: Some(json!({
"client_api_format": "openai:responses:compact",
"provider_api_format": "gemini:generate_content",
"model": "gpt-5",
"needs_conversion": true,
"has_envelope": false,
})),
status_code: 200,
headers: BTreeMap::from([("content-type".to_string(), "application/json".to_string())]),
body_json: Some(json!({
"responseId": "resp_cli_tool_123",
"candidates": [{
"content": {
"parts": [
{"text": "Need a tool."},
{"functionCall": {"name": "get_weather", "args": {"location": "Tokyo"}}}
],
"role": "model"
},
"finishReason": "STOP",
"index": 0
}],
"modelVersion": "gemini-cli-upstream",
"usageMetadata": {
"promptTokenCount": 3,
"candidatesTokenCount": 5,
"thoughtsTokenCount": 2,
"totalTokenCount": 10
}
})),
client_body_json: None,
body_base64: None,
telemetry: None,
};
let outcome = maybe_build_local_core_sync_finalize_response(
"trace-compact-tool-123",
&test_decision(),
&payload,
)
.expect("local finalize should succeed")
.expect("local finalize should match");
let report = outcome
.background_report
.expect("compact tool-call should downgrade to success report");
let client_body = report.client_body_json.expect("client body should exist");
assert_eq!(client_body["object"], "response.compaction");
assert_eq!(client_body["output"][1]["type"], "function_call");
}
#[test]
fn local_finalize_handles_openai_responses_openai_family_sync_response_even_when_conversion_flagged(
) {
let payload = GatewaySyncReportRequest {
trace_id: "trace-openai-responses-family-conversion-123".to_string(),
report_kind: "openai_responses_sync_finalize".to_string(),
report_context: Some(json!({
"client_api_format": "openai:responses",
"provider_api_format": "openai:responses:compact",
"model": "gpt-5",
"needs_conversion": true,
"has_envelope": false,
})),
status_code: 200,
headers: BTreeMap::from([("content-type".to_string(), "application/json".to_string())]),
body_json: Some(json!({
"id": "resp_cli_family_123",
"object": "response",
"status": "completed",
"model": "gpt-5",
"output": [{
"type": "message",
"id": openai_responses_message_item_id("resp_cli_family_123", 0),
"role": "assistant",
"status": "completed",
"content": [{
"type": "output_text",
"text": "Hello OpenAI family",
"annotations": []
}]
}],
"usage": {
"input_tokens": 3,
"output_tokens": 5,
"total_tokens": 8
}
})),
client_body_json: None,
body_base64: None,
telemetry: None,
};
let outcome = maybe_build_local_core_sync_finalize_response(
"trace-openai-responses-family-conversion-123",
&test_decision(),
&payload,
)
.expect("local finalize should succeed")
.expect("local finalize should match");
assert_eq!(outcome.response.status(), 200);
let report = outcome
.background_report
.expect("same-family finalize should downgrade to success report");
assert_eq!(report.report_kind, "openai_responses_sync_success");
assert_eq!(
report.body_json.expect("provider body should exist")["id"],
"resp_cli_family_123"
);
}
#[tokio::test]
async fn local_finalize_converts_openai_responses_null_error_to_claude_cli() {
let payload = GatewaySyncReportRequest {
trace_id: "trace-openai-responses-to-claude-cli-success".to_string(),
report_kind: "claude_cli_sync_finalize".to_string(),
report_context: Some(json!({
"client_api_format": "claude:messages",
"provider_api_format": "openai:responses",
"model": "claude-sonnet-4-5",
"mapped_model": "gpt-5",
"needs_conversion": true,
"has_envelope": false,
})),
status_code: 200,
headers: BTreeMap::from([("content-type".to_string(), "application/json".to_string())]),
body_json: Some(json!({
"id": "resp_completed_cli_123",
"object": "response",
"model": "gpt-5",
"status": "completed",
"error": null,
"output": [{
"type": "message",
"id": "msg_completed_cli_123",
"role": "assistant",
"status": "completed",
"content": [{
"type": "output_text",
"text": "Done",
"annotations": []
}]
}]
})),
client_body_json: None,
body_base64: None,
telemetry: None,
};
let outcome = maybe_build_local_core_sync_finalize_response(
"trace-openai-responses-to-claude-cli-success",
&test_decision(),
&payload,
)
.expect("local finalize should succeed")
.expect("local finalize should convert the response");
assert_eq!(outcome.response.status(), 200);
let response_body = to_bytes(outcome.response.into_body(), usize::MAX)
.await
.expect("response body should read");
let body: serde_json::Value =
serde_json::from_slice(&response_body).expect("response should be json");
assert_eq!(body["type"], "message");
assert_eq!(body["content"][0]["text"], "Done");
assert_eq!(body["stop_reason"], "end_turn");
}
#[test]
fn local_finalize_handles_openai_chat_stream_response_from_openai_chat() {
let body = concat!(
"data: {\"id\":\"chatcmpl_stream_direct_123\",\"object\":\"chat.completion.chunk\",\"created\":1,",
"\"model\":\"gpt-5\",\"choices\":[{\"index\":0,\"delta\":{\"role\":\"assistant\",\"content\":\"Hello\"},\"finish_reason\":null}]}\n\n",
"data: {\"id\":\"chatcmpl_stream_direct_123\",\"object\":\"chat.completion.chunk\",",
"\"model\":\"gpt-5\",\"choices\":[{\"index\":0,\"delta\":{\"content\":\" world\"},\"finish_reason\":null}]}\n\n",
"data: {\"id\":\"chatcmpl_stream_direct_123\",\"object\":\"chat.completion.chunk\",",
"\"model\":\"gpt-5\",\"choices\":[{\"index\":0,\"delta\":{},\"finish_reason\":\"stop\"}]}\n\n",
"data: [DONE]\n\n",
);
let payload = GatewaySyncReportRequest {
trace_id: "trace-openai-chat-stream-sync-123".to_string(),
report_kind: "openai_chat_sync_finalize".to_string(),
report_context: Some(json!({
"client_api_format": "openai:chat",
"provider_api_format": "openai:chat",
"model": "gpt-5",
"mapped_model": "gpt-5",
"needs_conversion": false,
"has_envelope": false,
})),
status_code: 200,
headers: BTreeMap::from([("content-type".to_string(), "text/event-stream".to_string())]),
body_json: None,
client_body_json: None,
body_base64: Some(base64::engine::general_purpose::STANDARD.encode(body.as_bytes())),
telemetry: None,
};
let outcome = maybe_build_local_core_sync_finalize_response(
"trace-openai-chat-stream-sync-123",
&test_decision(),
&payload,
)
.expect("local finalize should succeed")
.expect("local finalize should match");
let report = outcome
.background_report
.expect("stream finalize should downgrade to success report");
assert_eq!(report.report_kind, "openai_chat_sync_success");
let provider_body = report.body_json.expect("provider body should exist");
assert_eq!(provider_body["object"], "chat.completion");
assert_eq!(
provider_body["choices"][0]["message"]["content"],
"Hello world"
);
}
#[test]
fn local_finalize_handles_openai_responses_cross_format_stream_response_from_gemini() {
let body = concat!(
"data: {\"responseId\":\"resp_cli_stream_123\",\"candidates\":[{\"content\":{\"parts\":[{\"text\":\"Hello \"}],\"role\":\"model\"},\"index\":0}],\"modelVersion\":\"gemini-2.5-pro-upstream\"}\n\n",
"data: {\"responseId\":\"resp_cli_stream_123\",\"candidates\":[{\"content\":{\"parts\":[{\"text\":\"Hello Gemini CLI\"}],\"role\":\"model\"},\"finishReason\":\"STOP\",\"index\":0}],\"modelVersion\":\"gemini-2.5-pro-upstream\",\"usageMetadata\":{\"promptTokenCount\":2,\"candidatesTokenCount\":3,\"totalTokenCount\":5}}\n\n",
);
let payload = GatewaySyncReportRequest {
trace_id: "trace-openai-responses-xfmt-stream-123".to_string(),
report_kind: "openai_responses_sync_finalize".to_string(),
report_context: Some(json!({
"client_api_format": "openai:responses",
"provider_api_format": "gemini:generate_content",
"model": "gpt-5",
"mapped_model": "gemini-2.5-pro-upstream",
"needs_conversion": true,
"has_envelope": false,
})),
status_code: 200,
headers: BTreeMap::from([("content-type".to_string(), "text/event-stream".to_string())]),
body_json: None,
client_body_json: None,
body_base64: Some(base64::engine::general_purpose::STANDARD.encode(body.as_bytes())),
telemetry: None,
};
let outcome = maybe_build_local_core_sync_finalize_response(
"trace-openai-responses-xfmt-stream-123",
&test_decision(),
&payload,
)
.expect("local finalize should succeed")
.expect("local finalize should match");
let report = outcome
.background_report
.expect("cross-format stream finalize should downgrade to success report");
assert_eq!(report.report_kind, "openai_responses_sync_success");
let client_body = report.client_body_json.expect("client body should exist");
assert_eq!(client_body["object"], "response");
assert_eq!(
client_body["output"][0]["content"][0]["text"],
"Hello Gemini CLI"
);
}
#[test]
fn local_finalize_rejects_antigravity_usage_only_gemini_wrapper() {
let payload = GatewaySyncReportRequest {
trace_id: "trace-antigravity-empty-gemini-wrapper".to_string(),
report_kind: "gemini_chat_sync_finalize".to_string(),
report_context: Some(json!({
"client_api_format": "gemini:generate_content",
"provider_api_format": "gemini:generate_content",
"model": "gemini-3.5-flash",
"mapped_model": "gemini-3-flash-agent",
"needs_conversion": false,
"has_envelope": true,
"envelope_name": "antigravity:v1internal",
"upstream_is_stream": true,
})),
status_code: 200,
headers: BTreeMap::from([("content-type".to_string(), "application/json".to_string())]),
body_json: Some(json!({
"chunks": [{
"response": {
"responseId": "resp-usage-only",
"modelVersion": "gemini-3-flash-agent",
"usageMetadata": {
"promptTokenCount": 5528,
"totalTokenCount": 5528
}
},
"metadata": {},
"traceId": "trace-antigravity-empty-gemini-wrapper"
}],
"metadata": {
"stream": true,
"stored_chunks": 1,
"total_chunks": 1
}
})),
client_body_json: None,
body_base64: None,
telemetry: None,
};
let outcome = maybe_build_local_core_sync_finalize_response(
"trace-antigravity-empty-gemini-wrapper",
&test_decision(),
&payload,
)
.expect("local finalize should evaluate payload");
assert!(outcome.is_none());
}
#[test]
fn local_finalize_handles_openai_responses_compact_openai_family_stream_response_even_when_conversion_flagged(
) {
let body = concat!(
"event: response.completed\n",
"data: {\"type\":\"response.completed\",\"response\":{\"id\":\"resp_cli_family_stream_123\",\"object\":\"response\",\"model\":\"gpt-5\",\"status\":\"completed\",\"output\":[],\"usage\":{\"input_tokens\":1,\"output_tokens\":2,\"total_tokens\":3}}}\n\n",
);
let payload = GatewaySyncReportRequest {
trace_id: "trace-openai-compact-family-stream-123".to_string(),
report_kind: "openai_responses_compact_sync_finalize".to_string(),
report_context: Some(json!({
"client_api_format": "openai:responses:compact",
"provider_api_format": "openai:responses",
"model": "gpt-5",
"mapped_model": "gpt-5",
"needs_conversion": true,
"has_envelope": false,
})),
status_code: 200,
headers: BTreeMap::from([("content-type".to_string(), "text/event-stream".to_string())]),
body_json: None,
client_body_json: None,
body_base64: Some(base64::engine::general_purpose::STANDARD.encode(body.as_bytes())),
telemetry: None,
};
let outcome = maybe_build_local_core_sync_finalize_response(
"trace-openai-compact-family-stream-123",
&test_decision(),
&payload,
)
.expect("local finalize should succeed")
.expect("local finalize should match");
let report = outcome
.background_report
.expect("same-family stream finalize should downgrade to success report");
assert_eq!(report.report_kind, "openai_responses_compact_sync_success");
let provider_body = report.body_json.expect("provider body should exist");
assert_eq!(provider_body["object"], "response");
assert_eq!(provider_body["status"], "completed");
}
#[test]
fn local_finalize_preserves_provider_stream_body_for_same_format_stream_aggregated_to_sync() {
let body = concat!(
"event: response.output_text.delta\n",
"data: {\"type\":\"response.output_text.delta\",\"output_index\":0,\"content_index\":0,\"delta\":\"Hello sync\"}\n\n",
"event: response.completed\n",
"data: {\"type\":\"response.completed\",\"response\":{\"id\":\"resp_cli_samefmt_stream_123\",\"object\":\"response\",\"model\":\"gpt-5.4\",\"status\":\"completed\",\"output\":[{\"type\":\"message\",\"id\":\"msg_123\",\"role\":\"assistant\",\"status\":\"completed\",\"content\":[{\"type\":\"output_text\",\"text\":\"Hello sync\",\"annotations\":[]}]}],\"usage\":{\"input_tokens\":1,\"output_tokens\":2,\"total_tokens\":3}}}\n\n",
);
let payload = GatewaySyncReportRequest {
trace_id: "trace-openai-responses-samefmt-stream-123".to_string(),
report_kind: "openai_responses_sync_finalize".to_string(),
report_context: Some(json!({
"client_api_format": "openai:responses",
"provider_api_format": "openai:responses",
"model": "gpt-5.4",
"mapped_model": "gpt-5.4",
"needs_conversion": false,
"has_envelope": false,
"upstream_is_stream": true,
})),
status_code: 200,
headers: BTreeMap::from([("content-type".to_string(), "text/event-stream".to_string())]),
body_json: None,
client_body_json: None,
body_base64: Some(base64::engine::general_purpose::STANDARD.encode(body.as_bytes())),
telemetry: None,
};
let outcome = maybe_build_local_core_sync_finalize_response(
"trace-openai-responses-samefmt-stream-123",
&test_decision(),
&payload,
)
.expect("local finalize should succeed")
.expect("local finalize should match");
let report = outcome
.background_report
.expect("same-format stream finalize should downgrade to success report");
let client_body = report.client_body_json.expect("client body should exist");
assert!(report.body_json.is_none());
assert_eq!(
report.body_base64,
Some(base64::engine::general_purpose::STANDARD.encode(body.as_bytes()))
);
assert_eq!(client_body["object"], "response");
assert_eq!(client_body["status"], "completed");
assert_eq!(client_body["output"][0]["content"][0]["text"], "Hello sync");
}
#[test]
fn local_finalize_handles_openai_chat_cross_format_sync_response_from_claude() {
let payload = GatewaySyncReportRequest {
trace_id: "trace-openai-chat-xfmt-claude-sync-123".to_string(),
report_kind: "openai_chat_sync_finalize".to_string(),
report_context: Some(json!({
"client_api_format": "openai:chat",
"provider_api_format": "claude:messages",
"model": "gpt-5",
"mapped_model": "claude-sonnet-4",
"needs_conversion": true,
"has_envelope": false,
})),
status_code: 200,
headers: BTreeMap::from([("content-type".to_string(), "application/json".to_string())]),
body_json: Some(json!({
"id": "msg_claude_direct_123",
"type": "message",
"model": "claude-sonnet-4",
"role": "assistant",
"content": [{"type": "text", "text": "Hello Claude"}],
"stop_reason": "end_turn",
"usage": {
"input_tokens": 2,
"output_tokens": 3
}
})),
client_body_json: None,
body_base64: None,
telemetry: None,
};
let outcome = maybe_build_local_core_sync_finalize_response(
"trace-openai-chat-xfmt-claude-sync-123",
&test_decision(),
&payload,
)
.expect("local finalize should succeed")
.expect("local finalize should match");
let report = outcome
.background_report
.expect("cross-format finalize should downgrade to success report");
assert_eq!(report.report_kind, "openai_chat_sync_success");
assert_eq!(
report.body_json.expect("provider body should exist")["id"],
"msg_claude_direct_123"
);
let client_body = report.client_body_json.expect("client body should exist");
assert_eq!(client_body["object"], "chat.completion");
assert_eq!(
client_body["choices"][0]["message"]["content"],
"Hello Claude"
);
}
#[test]
fn local_finalize_handles_openai_chat_cross_format_sync_response_from_gemini() {
let payload = GatewaySyncReportRequest {
trace_id: "trace-openai-chat-xfmt-gemini-sync-123".to_string(),
report_kind: "openai_chat_sync_finalize".to_string(),
report_context: Some(json!({
"client_api_format": "openai:chat",
"provider_api_format": "gemini:generate_content",
"model": "gpt-5",
"mapped_model": "gemini-2.5-pro",
"needs_conversion": true,
"has_envelope": false,
})),
status_code: 200,
headers: BTreeMap::from([("content-type".to_string(), "application/json".to_string())]),
body_json: Some(json!({
"responseId": "resp_gemini_direct_123",
"candidates": [{
"content": {
"parts": [{"text": "Hello Gemini"}],
"role": "model"
},
"finishReason": "STOP",
"index": 0
}],
"modelVersion": "gemini-2.5-pro-upstream",
"usageMetadata": {
"promptTokenCount": 1,
"candidatesTokenCount": 2,
"totalTokenCount": 3
}
})),
client_body_json: None,
body_base64: None,
telemetry: None,
};
let outcome = maybe_build_local_core_sync_finalize_response(
"trace-openai-chat-xfmt-gemini-sync-123",
&test_decision(),
&payload,
)
.expect("local finalize should succeed")
.expect("local finalize should match");
let report = outcome
.background_report
.expect("cross-format finalize should downgrade to success report");
assert_eq!(report.report_kind, "openai_chat_sync_success");
assert_eq!(
report.body_json.expect("provider body should exist")["responseId"],
"resp_gemini_direct_123"
);
let client_body = report.client_body_json.expect("client body should exist");
assert_eq!(client_body["object"], "chat.completion");
assert_eq!(
client_body["choices"][0]["message"]["content"],
"Hello Gemini"
);
assert_eq!(client_body["usage"]["completion_tokens"], 2);
assert_eq!(client_body["usage"]["total_tokens"], 3);
}
#[test]
fn local_finalize_handles_openai_chat_cross_format_sync_response_from_openai_responses() {
let payload = GatewaySyncReportRequest {
trace_id: "trace-openai-chat-xfmt-openai-responses-sync-123".to_string(),
report_kind: "openai_chat_sync_finalize".to_string(),
report_context: Some(json!({
"client_api_format": "openai:chat",
"provider_api_format": "openai:responses",
"model": "gpt-5.4",
"mapped_model": "gpt-5.4",
"needs_conversion": true,
"has_envelope": false,
})),
status_code: 200,
headers: BTreeMap::from([("content-type".to_string(), "application/json".to_string())]),
body_json: Some(json!({
"id": "resp_cli_direct_123",
"object": "response",
"status": "completed",
"model": "gpt-5.4",
"output": [
{
"type": "message",
"id": "msg_cli_direct_123",
"role": "assistant",
"status": "completed",
"content": [{
"type": "output_text",
"text": "Hello CLI",
"annotations": []
}]
},
{
"type": "function_call",
"id": "fc_cli_direct_123",
"call_id": "call_weather_123",
"name": "get_weather",
"arguments": "{\"city\":\"SF\"}"
}
],
"usage": {
"input_tokens": 2,
"output_tokens": 3,
"total_tokens": 5
}
})),
client_body_json: None,
body_base64: None,
telemetry: None,
};
let outcome = maybe_build_local_core_sync_finalize_response(
"trace-openai-chat-xfmt-openai-responses-sync-123",
&test_decision(),
&payload,
)
.expect("local finalize should succeed")
.expect("local finalize should match");
let report = outcome
.background_report
.expect("cross-format finalize should downgrade to success report");
assert_eq!(report.report_kind, "openai_chat_sync_success");
assert_eq!(
report.body_json.expect("provider body should exist")["id"],
"resp_cli_direct_123"
);
let client_body = report.client_body_json.expect("client body should exist");
assert_eq!(client_body["object"], "chat.completion");
assert_eq!(client_body["choices"][0]["message"]["content"], "Hello CLI");
assert_eq!(
client_body["choices"][0]["message"]["tool_calls"][0]["id"],
"call_weather_123"
);
assert_eq!(
client_body["choices"][0]["message"]["tool_calls"][0]["function"]["name"],
"get_weather"
);
assert_eq!(
client_body["choices"][0]["message"]["tool_calls"][0]["function"]["arguments"],
"{\"city\":\"SF\"}"
);
assert_eq!(client_body["choices"][0]["finish_reason"], "tool_calls");
assert_eq!(client_body["usage"]["completion_tokens"], 3);
assert_eq!(client_body["usage"]["total_tokens"], 5);
}
#[test]
fn local_finalize_aggregates_openai_responses_capture_envelope_before_chat_conversion() {
let payload = GatewaySyncReportRequest {
trace_id: "trace-openai-chat-capture-envelope-sync-123".to_string(),
report_kind: "openai_chat_sync_finalize".to_string(),
report_context: Some(json!({
"client_api_format": "openai:chat",
"provider_api_format": "openai:responses",
"model": "gpt-5.6-luna",
"mapped_model": "gpt-5.6-luna",
"needs_conversion": true,
"has_envelope": false,
})),
status_code: 200,
headers: BTreeMap::from([("content-type".to_string(), "application/json".to_string())]),
body_json: Some(json!({
"chunks": [
{
"type": "response.output_text.delta",
"response_id": "resp_capture_gateway_123",
"output_index": 0,
"content_index": 0,
"delta": "Gateway "
},
{
"type": "response.output_text.done",
"response_id": "resp_capture_gateway_123",
"output_index": 0,
"content_index": 0,
"text": "Gateway capture"
},
{
"type": "response.completed",
"response": {
"id": "resp_capture_gateway_123",
"object": "response",
"status": "completed",
"model": "gpt-5.6-luna",
"output": [],
"usage": {
"input_tokens": 2,
"output_tokens": 3,
"total_tokens": 5
}
}
}
],
"metadata": {}
})),
client_body_json: None,
body_base64: None,
telemetry: None,
};
let outcome = maybe_build_local_core_sync_finalize_response(
"trace-openai-chat-capture-envelope-sync-123",
&test_decision(),
&payload,
)
.expect("capture envelope finalize should succeed")
.expect("capture envelope finalize should match");
let report = outcome
.background_report
.expect("capture envelope conversion should produce a success report");
assert_eq!(report.report_kind, "openai_chat_sync_success");
let provider_body = report
.body_json
.expect("aggregated provider body should exist");
assert_eq!(provider_body["id"], "resp_capture_gateway_123");
assert_eq!(
provider_body["output"][0]["content"][0]["text"],
"Gateway capture"
);
assert!(provider_body.get("chunks").is_none());
let client_body = report
.client_body_json
.expect("converted client body should exist");
assert_eq!(
client_body["choices"][0]["message"]["content"],
"Gateway capture"
);
assert_eq!(client_body["usage"]["prompt_tokens"], 2);
assert_eq!(client_body["usage"]["completion_tokens"], 3);
assert_eq!(client_body["usage"]["total_tokens"], 5);
}
#[test]
fn local_finalize_handles_claude_chat_cross_format_sync_response_from_openai_chat() {
let payload = GatewaySyncReportRequest {
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:messages",
"provider_api_format": "openai:chat",
"model": "claude-sonnet-4-5",
"mapped_model": "gpt-5",
"needs_conversion": true,
"has_envelope": false,
})),
status_code: 200,
headers: BTreeMap::from([("content-type".to_string(), "application/json".to_string())]),
body_json: Some(json!({
"id": "chatcmpl_openai_to_claude_123",
"object": "chat.completion",
"model": "gpt-5",
"choices": [{
"index": 0,
"message": {
"role": "assistant",
"content": "Hello OpenAI to Claude"
},
"finish_reason": "stop"
}],
"usage": {
"prompt_tokens": 2,
"completion_tokens": 3,
"total_tokens": 5
}
})),
client_body_json: None,
body_base64: None,
telemetry: None,
};
let outcome = maybe_build_local_core_sync_finalize_response(
"trace-claude-chat-xfmt-openai-sync-123",
&GatewayControlDecision {
public_path: "/v1/messages".to_string(),
public_query_string: None,
route_class: Some("ai_public".to_string()),
route_family: Some("claude".to_string()),
route_kind: Some("chat".to_string()),
client_surface: None,
api_operation: None,
gateway_credential_carrier: None,
request_auth_channel: None,
auth_endpoint_signature: Some("claude:messages".to_string()),
execution_runtime_candidate: true,
auth_context: None,
admin_principal: None,
local_auth_rejection: None,
model_directive_policy: Default::default(),
},
&payload,
)
.expect("local finalize should succeed")
.expect("local finalize should match");
let report = outcome
.background_report
.expect("cross-format finalize should downgrade to success report");
assert_eq!(report.report_kind, "claude_chat_sync_success");
let client_body = report.client_body_json.expect("client body should exist");
assert_eq!(client_body["type"], "message");
assert_eq!(client_body["role"], "assistant");
assert_eq!(client_body["content"][0]["text"], "Hello OpenAI to Claude");
assert_eq!(client_body["usage"]["input_tokens"], 2);
assert_eq!(client_body["usage"]["output_tokens"], 3);
}
#[test]
fn local_finalize_handles_gemini_cli_cross_format_sync_response_from_claude_cli() {
let payload = GatewaySyncReportRequest {
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:generate_content",
"provider_api_format": "claude:messages",
"model": "gemini-cli",
"mapped_model": "claude-code",
"needs_conversion": true,
"has_envelope": false,
})),
status_code: 200,
headers: BTreeMap::from([("content-type".to_string(), "application/json".to_string())]),
body_json: Some(json!({
"id": "msg_claude_cli_to_gemini_123",
"type": "message",
"model": "claude-code",
"role": "assistant",
"content": [{
"type": "text",
"text": "Hello Claude CLI to Gemini"
}],
"stop_reason": "end_turn",
"usage": {
"input_tokens": 4,
"output_tokens": 6
}
})),
client_body_json: None,
body_base64: None,
telemetry: None,
};
let outcome = maybe_build_local_core_sync_finalize_response(
"trace-gemini-cli-xfmt-claude-sync-123",
&GatewayControlDecision {
public_path: "/v1beta/models/gemini-cli:generateContent".to_string(),
public_query_string: None,
route_class: Some("ai_public".to_string()),
route_family: Some("gemini".to_string()),
route_kind: Some("cli".to_string()),
client_surface: None,
api_operation: None,
gateway_credential_carrier: None,
request_auth_channel: None,
auth_endpoint_signature: Some("gemini:generate_content".to_string()),
execution_runtime_candidate: true,
auth_context: None,
admin_principal: None,
local_auth_rejection: None,
model_directive_policy: Default::default(),
},
&payload,
)
.expect("local finalize should succeed")
.expect("local finalize should match");
let report = outcome
.background_report
.expect("cross-format finalize should downgrade to success report");
assert_eq!(report.report_kind, "gemini_cli_sync_success");
let client_body = report.client_body_json.expect("client body should exist");
assert_eq!(
client_body["candidates"][0]["content"]["parts"][0]["text"],
"Hello Claude CLI to Gemini"
);
assert_eq!(client_body["usageMetadata"]["promptTokenCount"], 4);
assert_eq!(client_body["usageMetadata"]["candidatesTokenCount"], 6);
}
#[test]
fn local_finalize_handles_kiro_claude_cli_stream_tool_use_response() {
let payload = build_kiro_claude_cli_sync_finalize_payload(
[
encode_kiro_event_frame("assistantResponseEvent", json!({"content": "Need a tool."})),
encode_kiro_event_frame(
"toolUseEvent",
json!({
"name": "get_weather",
"toolUseId": "tool_123",
"input": {"city": "SF"},
"stop": true
}),
),
]
.concat(),
);
let outcome = maybe_build_local_core_sync_finalize_response(
"trace-kiro-cli-tool-123",
&test_decision(),
&payload,
)
.expect("local finalize should succeed")
.expect("local finalize should match");
let report = outcome
.background_report
.expect("same-format finalize should downgrade to success report");
assert_eq!(report.report_kind, "claude_cli_sync_success");
let body = report.body_json.expect("provider body should exist");
assert_eq!(body["content"][0]["text"], "Need a tool.");
assert_eq!(body["content"][1]["type"], "tool_use");
assert_eq!(body["content"][1]["id"], "tool_123");
assert_eq!(body["content"][1]["name"], "get_weather");
assert_eq!(body["content"][1]["input"]["city"], "SF");
assert_eq!(body["stop_reason"], "tool_use");
}
#[test]
fn local_finalize_handles_kiro_claude_cli_stream_content_length_exceeded_response() {
let payload = build_kiro_claude_cli_sync_finalize_payload(
[
encode_kiro_event_frame(
"assistantResponseEvent",
json!({"content": "Hello from Kiro"}),
),
encode_kiro_exception_frame("ContentLengthExceededException"),
]
.concat(),
);
let outcome = maybe_build_local_core_sync_finalize_response(
"trace-kiro-cli-max-tokens-123",
&test_decision(),
&payload,
)
.expect("local finalize should succeed")
.expect("local finalize should match");
let report = outcome
.background_report
.expect("same-format finalize should downgrade to success report");
let body = report.body_json.expect("provider body should exist");
assert_eq!(body["content"][0]["text"], "Hello from Kiro");
assert_eq!(body["stop_reason"], "max_tokens");
}
#[test]
fn local_finalize_rejects_kiro_claude_cli_stream_upstream_error_frame() {
let payload = build_kiro_claude_cli_sync_finalize_payload(
[
encode_kiro_event_frame(
"assistantResponseEvent",
json!({"content": "Partial output"}),
),
encode_kiro_error_frame("ThrottlingException"),
]
.concat(),
);
let outcome = maybe_build_local_core_sync_finalize_response(
"trace-kiro-cli-error-123",
&test_decision(),
&payload,
)
.expect("local finalize should not error");
assert!(
outcome.is_none(),
"embedded stream errors should fall back to Python finalize instead of being reported as success"
);
}
#[tokio::test]
async fn local_finalize_handles_openai_image_stream_response_from_output_item_done() {
let payload = GatewaySyncReportRequest {
trace_id: "trace-openai-image-finalize-123".to_string(),
report_kind: "openai_image_sync_finalize".to_string(),
report_context: Some(json!({
"client_api_format": "openai:image",
"provider_api_format": "openai:image",
"model": "gpt-image-2",
"mapped_model": "gpt-5.4",
"image_request": {
"operation": "generate",
"response_format": "b64_json",
"output_format": "png"
}
})),
status_code: 200,
headers: BTreeMap::from([(
"content-type".to_string(),
"text/event-stream".to_string(),
)]),
body_json: None,
client_body_json: None,
body_base64: Some(base64::engine::general_purpose::STANDARD.encode(
concat!(
"event: response.created\n",
"data: {\"type\":\"response.created\",\"response\":{\"id\":\"resp_img_123\",\"object\":\"response\",\"created_at\":1776839946,\"status\":\"in_progress\",\"model\":\"gpt-5.4\"}}\n\n",
"event: response.output_item.done\n",
"data: {\"type\":\"response.output_item.done\",\"output_index\":0,\"item\":{\"id\":\"ig_123\",\"type\":\"image_generation_call\",\"status\":\"generating\",\"output_format\":\"png\",\"quality\":\"medium\",\"size\":\"1024x1536\",\"revised_prompt\":\"revised history prompt\",\"result\":\"aGVsbG8=\"}}\n\n",
"event: response.completed\n",
"data: {\"type\":\"response.completed\",\"response\":{\"id\":\"resp_img_123\",\"object\":\"response\",\"model\":\"gpt-5.4\",\"status\":\"completed\",\"output\":[],\"usage\":{\"input_tokens\":2440,\"output_tokens\":184,\"total_tokens\":2624},\"tool_usage\":{\"image_gen\":{\"input_tokens\":171,\"input_tokens_details\":{\"image_tokens\":0,\"text_tokens\":171},\"output_tokens\":1372,\"output_tokens_details\":{\"image_tokens\":1372,\"text_tokens\":0},\"total_tokens\":1543}}}}\n\n"
)
.as_bytes(),
)),
telemetry: None,
};
let outcome = maybe_build_local_core_sync_finalize_response(
"trace-openai-image-finalize-123",
&test_decision(),
&payload,
)
.expect("image finalize should succeed")
.expect("image finalize should match");
let response_body = to_bytes(outcome.response.into_body(), usize::MAX)
.await
.expect("response body should read");
let response_json: serde_json::Value =
serde_json::from_slice(&response_body).expect("response should be json");
assert_eq!(response_json["created"], 1776839946);
assert_eq!(response_json["data"][0]["b64_json"], "aGVsbG8=");
assert_eq!(
response_json["data"][0]["revised_prompt"],
"revised history prompt"
);
assert_eq!(response_json["usage"]["input_tokens"], 171);
assert_eq!(response_json["usage"]["output_tokens"], 1372);
let report = outcome
.background_report
.expect("image finalize should emit success report");
let provider_body = report.body_json.expect("provider body should exist");
assert_eq!(provider_body["usage"]["input_tokens"], 171);
assert_eq!(provider_body["usage"]["output_tokens"], 1372);
assert_eq!(report.report_kind, "openai_image_sync_success");
assert_eq!(
report.client_body_json.expect("client body should exist")["data"][0]["b64_json"],
"aGVsbG8="
);
}
#[tokio::test]
async fn local_finalize_returns_b64_json_even_when_url_response_format_requested() {
let payload = GatewaySyncReportRequest {
trace_id: "trace-openai-image-finalize-url-123".to_string(),
report_kind: "openai_image_sync_finalize".to_string(),
report_context: Some(json!({
"client_api_format": "openai:image",
"provider_api_format": "openai:image",
"model": "dall-e-3",
"mapped_model": "gpt-5.4",
"image_request": {
"operation": "generate",
"response_format": "url",
"output_format": "webp"
}
})),
status_code: 200,
headers: BTreeMap::from([(
"content-type".to_string(),
"text/event-stream".to_string(),
)]),
body_json: None,
client_body_json: None,
body_base64: Some(base64::engine::general_purpose::STANDARD.encode(
concat!(
"event: response.created\n",
"data: {\"type\":\"response.created\",\"response\":{\"id\":\"resp_img_url_123\",\"object\":\"response\",\"created_at\":1776839946,\"status\":\"in_progress\",\"model\":\"gpt-5.4\"}}\n\n",
"event: response.output_item.done\n",
"data: {\"type\":\"response.output_item.done\",\"output_index\":0,\"item\":{\"id\":\"ig_url_123\",\"type\":\"image_generation_call\",\"status\":\"completed\",\"output_format\":\"webp\",\"revised_prompt\":\"revised webp prompt\",\"result\":\"aGVsbG8=\"}}\n\n",
"event: response.completed\n",
"data: {\"type\":\"response.completed\",\"response\":{\"id\":\"resp_img_url_123\",\"object\":\"response\",\"model\":\"gpt-5.4\",\"status\":\"completed\",\"output\":[],\"tool_usage\":{\"image_gen\":{\"input_tokens\":11,\"output_tokens\":22,\"total_tokens\":33}}}}\n\n"
)
.as_bytes(),
)),
telemetry: None,
};
let outcome = maybe_build_local_core_sync_finalize_response(
"trace-openai-image-finalize-url-123",
&test_decision(),
&payload,
)
.expect("image finalize should succeed")
.expect("image finalize should match");
let response_body = to_bytes(outcome.response.into_body(), usize::MAX)
.await
.expect("response body should read");
let response_json: serde_json::Value =
serde_json::from_slice(&response_body).expect("response should be json");
assert_eq!(response_json["data"][0]["b64_json"], "aGVsbG8=");
assert!(response_json["data"][0].get("url").is_none());
assert_eq!(
response_json["data"][0]["revised_prompt"],
"revised webp prompt"
);
}
#[tokio::test]
async fn local_finalize_defaults_gpt_image_stream_response_to_b64_json() {
let payload = GatewaySyncReportRequest {
trace_id: "trace-openai-image-finalize-default-b64-123".to_string(),
report_kind: "openai_image_sync_finalize".to_string(),
report_context: Some(json!({
"client_api_format": "openai:image",
"provider_api_format": "openai:image",
"model": "gpt-image-2",
"mapped_model": "gpt-5.4",
"image_request": {
"operation": "generate",
"output_format": "png"
}
})),
status_code: 200,
headers: BTreeMap::from([(
"content-type".to_string(),
"text/event-stream".to_string(),
)]),
body_json: None,
client_body_json: None,
body_base64: Some(base64::engine::general_purpose::STANDARD.encode(
concat!(
"event: response.output_item.done\n",
"data: {\"type\":\"response.output_item.done\",\"output_index\":0,\"item\":{\"id\":\"ig_default_123\",\"type\":\"image_generation_call\",\"output_format\":\"png\",\"result\":\"aGVsbG8=\"}}\n\n",
"event: response.completed\n",
"data: {\"type\":\"response.completed\",\"response\":{\"id\":\"resp_img_default_123\",\"object\":\"response\",\"model\":\"gpt-5.4\",\"status\":\"completed\",\"output\":[]}}\n\n"
)
.as_bytes(),
)),
telemetry: None,
};
let outcome = maybe_build_local_core_sync_finalize_response(
"trace-openai-image-finalize-default-b64-123",
&test_decision(),
&payload,
)
.expect("image finalize should succeed")
.expect("image finalize should match");
let response_body = to_bytes(outcome.response.into_body(), usize::MAX)
.await
.expect("response body should read");
let response_json: serde_json::Value =
serde_json::from_slice(&response_body).expect("response should be json");
assert_eq!(response_json["data"][0]["b64_json"], "aGVsbG8=");
assert!(response_json["data"][0].get("url").is_none());
}
#[tokio::test]
async fn local_finalize_forces_gpt_image_stream_response_to_b64_json_even_when_url_requested() {
let payload = GatewaySyncReportRequest {
trace_id: "trace-openai-image-finalize-force-b64-123".to_string(),
report_kind: "openai_image_sync_finalize".to_string(),
report_context: Some(json!({
"client_api_format": "openai:image",
"provider_api_format": "openai:image",
"model": "gpt-image-2",
"mapped_model": "gpt-5.4",
"image_request": {
"operation": "generate",
"response_format": "url",
"output_format": "png"
}
})),
status_code: 200,
headers: BTreeMap::from([(
"content-type".to_string(),
"text/event-stream".to_string(),
)]),
body_json: None,
client_body_json: None,
body_base64: Some(base64::engine::general_purpose::STANDARD.encode(
concat!(
"event: response.output_item.done\n",
"data: {\"type\":\"response.output_item.done\",\"output_index\":0,\"item\":{\"id\":\"ig_force_123\",\"type\":\"image_generation_call\",\"output_format\":\"png\",\"result\":\"aGVsbG8=\"}}\n\n",
"event: response.completed\n",
"data: {\"type\":\"response.completed\",\"response\":{\"id\":\"resp_img_force_123\",\"object\":\"response\",\"model\":\"gpt-5.4\",\"status\":\"completed\",\"output\":[]}}\n\n"
)
.as_bytes(),
)),
telemetry: None,
};
let outcome = maybe_build_local_core_sync_finalize_response(
"trace-openai-image-finalize-force-b64-123",
&test_decision(),
&payload,
)
.expect("image finalize should succeed")
.expect("image finalize should match");
let response_body = to_bytes(outcome.response.into_body(), usize::MAX)
.await
.expect("response body should read");
let response_json: serde_json::Value =
serde_json::from_slice(&response_body).expect("response should be json");
assert_eq!(response_json["data"][0]["b64_json"], "aGVsbG8=");
assert!(response_json["data"][0].get("url").is_none());
}