mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-01 17:00:21 +08:00
migrate ai format conversion to responses adapters
This commit is contained in:
@@ -106,6 +106,8 @@ pub(crate) fn should_fallback_to_control_sync(
|
||||
| "openai_video_remix_sync"
|
||||
| "gemini_video_create_sync"
|
||||
| "openai_chat_sync"
|
||||
| "openai_responses_sync"
|
||||
| "openai_responses_compact_sync"
|
||||
| "openai_cli_sync"
|
||||
| "openai_compact_sync"
|
||||
| "claude_chat_sync"
|
||||
@@ -151,6 +153,8 @@ pub(crate) fn resolve_core_sync_error_finalize_report_kind(
|
||||
|
||||
let report_kind = match plan_kind {
|
||||
"openai_chat_sync" => "openai_chat_sync_finalize",
|
||||
"openai_responses_sync" => "openai_responses_sync_finalize",
|
||||
"openai_responses_compact_sync" => "openai_responses_compact_sync_finalize",
|
||||
"openai_cli_sync" => "openai_cli_sync_finalize",
|
||||
"openai_compact_sync" => "openai_compact_sync_finalize",
|
||||
"claude_chat_sync" => "claude_chat_sync_finalize",
|
||||
@@ -277,6 +281,8 @@ pub(crate) fn should_fallback_to_control_stream(
|
||||
"openai_chat_stream"
|
||||
| "claude_chat_stream"
|
||||
| "gemini_chat_stream"
|
||||
| "openai_responses_stream"
|
||||
| "openai_responses_compact_stream"
|
||||
| "openai_cli_stream"
|
||||
| "openai_compact_stream"
|
||||
| "claude_cli_stream"
|
||||
@@ -296,6 +302,8 @@ pub(crate) fn resolve_core_stream_error_finalize_report_kind(
|
||||
"openai_chat_stream" => "openai_chat_sync_finalize",
|
||||
"claude_chat_stream" => "claude_chat_sync_finalize",
|
||||
"gemini_chat_stream" => "gemini_chat_sync_finalize",
|
||||
"openai_responses_stream" => "openai_responses_sync_finalize",
|
||||
"openai_responses_compact_stream" => "openai_responses_compact_sync_finalize",
|
||||
"openai_cli_stream" => "openai_cli_sync_finalize",
|
||||
"openai_compact_stream" => "openai_compact_sync_finalize",
|
||||
"claude_cli_stream" => "claude_cli_sync_finalize",
|
||||
@@ -312,6 +320,8 @@ pub(crate) fn resolve_core_stream_direct_finalize_report_kind(plan_kind: &str) -
|
||||
"openai_image_stream" => "openai_image_sync_finalize",
|
||||
"claude_chat_stream" => "claude_chat_sync_finalize",
|
||||
"gemini_chat_stream" => "gemini_chat_sync_finalize",
|
||||
"openai_responses_stream" => "openai_responses_sync_finalize",
|
||||
"openai_responses_compact_stream" => "openai_responses_compact_sync_finalize",
|
||||
"openai_cli_stream" => "openai_cli_sync_finalize",
|
||||
"openai_compact_stream" => "openai_compact_sync_finalize",
|
||||
"claude_cli_stream" => "claude_cli_sync_finalize",
|
||||
|
||||
@@ -281,6 +281,9 @@ fn merge_stream_terminal_summary(
|
||||
current_summary.model = observed.model;
|
||||
}
|
||||
current_summary.observed_finish |= observed.observed_finish;
|
||||
current_summary.unknown_event_count = current_summary
|
||||
.unknown_event_count
|
||||
.saturating_add(observed.unknown_event_count);
|
||||
if current_summary.parser_error.is_none() {
|
||||
current_summary.parser_error = observed.parser_error;
|
||||
}
|
||||
@@ -2270,12 +2273,14 @@ mod tests {
|
||||
Some(ExecutionStreamTerminalSummary {
|
||||
standardized_usage: Some(runtime_usage),
|
||||
model: Some("gpt-5.5".to_string()),
|
||||
unknown_event_count: 1,
|
||||
..ExecutionStreamTerminalSummary::default()
|
||||
}),
|
||||
Some(ExecutionStreamTerminalSummary {
|
||||
standardized_usage: Some(observed_usage),
|
||||
response_id: Some("resp_123".to_string()),
|
||||
observed_finish: true,
|
||||
unknown_event_count: 2,
|
||||
..ExecutionStreamTerminalSummary::default()
|
||||
}),
|
||||
)
|
||||
@@ -2289,6 +2294,7 @@ mod tests {
|
||||
assert_eq!(merged.model.as_deref(), Some("gpt-5.5"));
|
||||
assert_eq!(merged.response_id.as_deref(), Some("resp_123"));
|
||||
assert!(merged.observed_finish);
|
||||
assert_eq!(merged.unknown_event_count, 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -2431,8 +2437,8 @@ mod tests {
|
||||
"stream": true
|
||||
})),
|
||||
stream: true,
|
||||
client_api_format: "openai:cli".into(),
|
||||
provider_api_format: "openai:cli".into(),
|
||||
client_api_format: "openai:responses".into(),
|
||||
provider_api_format: "openai:responses".into(),
|
||||
model_name: Some("gpt-5.4".into()),
|
||||
proxy: None,
|
||||
tls_profile: None,
|
||||
@@ -2447,7 +2453,7 @@ mod tests {
|
||||
Some("ai_public".to_string()),
|
||||
Some("openai".to_string()),
|
||||
Some("cli".to_string()),
|
||||
Some("openai:cli".to_string()),
|
||||
Some("openai:responses".to_string()),
|
||||
)
|
||||
.with_execution_runtime_candidate(true);
|
||||
|
||||
@@ -2456,11 +2462,11 @@ mod tests {
|
||||
plan,
|
||||
"trace-live-stream-first-data",
|
||||
&decision,
|
||||
"openai_cli_stream",
|
||||
"openai_responses_stream",
|
||||
None,
|
||||
Some(json!({
|
||||
"provider_api_format": "openai:cli",
|
||||
"client_api_format": "openai:cli",
|
||||
"provider_api_format": "openai:responses",
|
||||
"client_api_format": "openai:responses",
|
||||
})),
|
||||
)
|
||||
.await
|
||||
@@ -2552,8 +2558,8 @@ mod tests {
|
||||
"stream": true
|
||||
})),
|
||||
stream: true,
|
||||
client_api_format: "openai:cli".into(),
|
||||
provider_api_format: "openai:cli".into(),
|
||||
client_api_format: "openai:responses".into(),
|
||||
provider_api_format: "openai:responses".into(),
|
||||
model_name: Some("gpt-5.4".into()),
|
||||
proxy: None,
|
||||
tls_profile: None,
|
||||
@@ -2568,7 +2574,7 @@ mod tests {
|
||||
Some("ai_public".to_string()),
|
||||
Some("openai".to_string()),
|
||||
Some("cli".to_string()),
|
||||
Some("openai:cli".to_string()),
|
||||
Some("openai:responses".to_string()),
|
||||
)
|
||||
.with_execution_runtime_candidate(true);
|
||||
|
||||
@@ -2577,11 +2583,11 @@ mod tests {
|
||||
plan,
|
||||
"trace-remote-runtime-sync-json-stream",
|
||||
&decision,
|
||||
"openai_cli_stream",
|
||||
"openai_responses_stream",
|
||||
None,
|
||||
Some(json!({
|
||||
"provider_api_format": "openai:cli",
|
||||
"client_api_format": "openai:cli",
|
||||
"provider_api_format": "openai:responses",
|
||||
"client_api_format": "openai:responses",
|
||||
})),
|
||||
)
|
||||
.await
|
||||
|
||||
@@ -982,8 +982,8 @@ mod tests {
|
||||
"stream": true
|
||||
})),
|
||||
stream: true,
|
||||
client_api_format: "openai:cli".to_string(),
|
||||
provider_api_format: "openai:cli".to_string(),
|
||||
client_api_format: "openai:responses".to_string(),
|
||||
provider_api_format: "openai:responses".to_string(),
|
||||
model_name: Some("gpt-5.4".into()),
|
||||
proxy: None,
|
||||
tls_profile: None,
|
||||
|
||||
@@ -5,9 +5,10 @@ use serde_json::json;
|
||||
|
||||
use crate::ai_pipeline_api::{
|
||||
build_gemini_stream_plan_from_decision, build_gemini_sync_plan_from_decision,
|
||||
build_openai_cli_stream_plan_from_decision, build_openai_cli_sync_plan_from_decision,
|
||||
build_passthrough_sync_plan_from_decision, build_standard_stream_plan_from_decision,
|
||||
build_standard_sync_plan_from_decision, GatewayControlSyncDecisionResponse,
|
||||
build_openai_responses_stream_plan_from_decision,
|
||||
build_openai_responses_sync_plan_from_decision, build_passthrough_sync_plan_from_decision,
|
||||
build_standard_stream_plan_from_decision, build_standard_sync_plan_from_decision,
|
||||
GatewayControlSyncDecisionResponse,
|
||||
};
|
||||
use crate::execution_runtime::submission::{
|
||||
build_best_effort_local_core_error_body, resolve_core_error_background_report_kind,
|
||||
@@ -102,10 +103,21 @@ fn resolve_core_error_background_report_kind_maps_all_core_finalize_kinds() {
|
||||
("openai_chat_sync_finalize", Some("openai_chat_sync_error")),
|
||||
("claude_chat_sync_finalize", Some("claude_chat_sync_error")),
|
||||
("gemini_chat_sync_finalize", Some("gemini_chat_sync_error")),
|
||||
("openai_cli_sync_finalize", Some("openai_cli_sync_error")),
|
||||
(
|
||||
"openai_responses_sync_finalize",
|
||||
Some("openai_responses_sync_error"),
|
||||
),
|
||||
(
|
||||
"openai_responses_compact_sync_finalize",
|
||||
Some("openai_responses_compact_sync_error"),
|
||||
),
|
||||
(
|
||||
"openai_cli_sync_finalize",
|
||||
Some("openai_responses_sync_error"),
|
||||
),
|
||||
(
|
||||
"openai_compact_sync_finalize",
|
||||
Some("openai_compact_sync_error"),
|
||||
Some("openai_responses_sync_error"),
|
||||
),
|
||||
("claude_cli_sync_finalize", Some("claude_cli_sync_error")),
|
||||
("gemini_cli_sync_finalize", Some("gemini_cli_sync_error")),
|
||||
@@ -138,10 +150,21 @@ fn resolve_core_success_background_report_kind_maps_all_core_finalize_kinds() {
|
||||
"gemini_chat_sync_finalize",
|
||||
Some("gemini_chat_sync_success"),
|
||||
),
|
||||
("openai_cli_sync_finalize", Some("openai_cli_sync_success")),
|
||||
(
|
||||
"openai_responses_sync_finalize",
|
||||
Some("openai_responses_sync_success"),
|
||||
),
|
||||
(
|
||||
"openai_responses_compact_sync_finalize",
|
||||
Some("openai_responses_compact_sync_success"),
|
||||
),
|
||||
(
|
||||
"openai_cli_sync_finalize",
|
||||
Some("openai_responses_sync_success"),
|
||||
),
|
||||
(
|
||||
"openai_compact_sync_finalize",
|
||||
Some("openai_cli_sync_success"),
|
||||
Some("openai_responses_sync_success"),
|
||||
),
|
||||
("claude_cli_sync_finalize", Some("claude_cli_sync_success")),
|
||||
("gemini_cli_sync_finalize", Some("gemini_cli_sync_success")),
|
||||
@@ -195,10 +218,10 @@ fn build_best_effort_local_core_error_body_converts_gemini_chat_error_to_openai_
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn build_best_effort_local_core_error_body_converts_claude_cli_error_to_openai_cli() {
|
||||
fn build_best_effort_local_core_error_body_converts_claude_cli_error_to_openai_responses() {
|
||||
let payload = core_finalize_payload(
|
||||
"openai_cli_sync_finalize",
|
||||
"openai:cli",
|
||||
"openai_responses_sync_finalize",
|
||||
"openai:responses",
|
||||
"claude:cli",
|
||||
401,
|
||||
json!({
|
||||
@@ -300,10 +323,10 @@ fn build_best_effort_local_core_error_body_converts_sync_errors_across_standard_
|
||||
}),
|
||||
),
|
||||
(
|
||||
"gemini cli -> openai cli",
|
||||
"gemini cli -> openai responses",
|
||||
core_finalize_payload(
|
||||
"openai_cli_sync_finalize",
|
||||
"openai:cli",
|
||||
"openai_responses_sync_finalize",
|
||||
"openai:responses",
|
||||
"gemini:cli",
|
||||
429,
|
||||
json!({
|
||||
@@ -388,7 +411,7 @@ fn resolve_local_core_error_response_body_json_parses_body_base64_json_for_cross
|
||||
let mut payload = core_finalize_payload(
|
||||
"claude_cli_sync_finalize",
|
||||
"claude:cli",
|
||||
"openai:cli",
|
||||
"openai:responses",
|
||||
401,
|
||||
json!({}),
|
||||
);
|
||||
@@ -419,7 +442,7 @@ fn resolve_local_core_error_response_body_json_builds_client_error_from_plain_te
|
||||
let mut payload = core_finalize_payload(
|
||||
"claude_cli_sync_finalize",
|
||||
"claude:cli",
|
||||
"openai:cli",
|
||||
"openai:responses",
|
||||
400,
|
||||
json!({}),
|
||||
);
|
||||
@@ -515,18 +538,18 @@ fn generic_decision_builders_require_exact_provider_request() {
|
||||
let parts = test_parts();
|
||||
let body_json = json!({"messages":[{"role":"user","content":"hi"}]});
|
||||
|
||||
assert!(build_openai_cli_stream_plan_from_decision(
|
||||
assert!(build_openai_responses_stream_plan_from_decision(
|
||||
&parts,
|
||||
&body_json,
|
||||
missing_exact_provider_request_payload("openai_cli_stream"),
|
||||
missing_exact_provider_request_payload("openai_responses_stream"),
|
||||
false,
|
||||
)
|
||||
.expect("builder should not error")
|
||||
.is_none());
|
||||
assert!(build_openai_cli_stream_plan_from_decision(
|
||||
assert!(build_openai_responses_stream_plan_from_decision(
|
||||
&parts,
|
||||
&body_json,
|
||||
missing_exact_provider_request_payload("openai_compact_stream"),
|
||||
missing_exact_provider_request_payload("openai_responses_compact_stream"),
|
||||
true,
|
||||
)
|
||||
.expect("builder should not error")
|
||||
@@ -546,10 +569,10 @@ fn generic_decision_builders_require_exact_provider_request() {
|
||||
)
|
||||
.expect("builder should not error")
|
||||
.is_none());
|
||||
assert!(build_openai_cli_sync_plan_from_decision(
|
||||
assert!(build_openai_responses_sync_plan_from_decision(
|
||||
&parts,
|
||||
&body_json,
|
||||
missing_exact_provider_request_payload("openai_cli_sync"),
|
||||
missing_exact_provider_request_payload("openai_responses_sync"),
|
||||
false,
|
||||
)
|
||||
.expect("builder should not error")
|
||||
@@ -605,7 +628,7 @@ fn passthrough_sync_plan_uses_provider_request_method_override() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn openai_cli_sync_plan_injects_auth_header_when_exact_headers_omit_it() {
|
||||
fn openai_responses_sync_plan_injects_auth_header_when_exact_headers_omit_it() {
|
||||
let request = Request::builder()
|
||||
.method("POST")
|
||||
.uri("/v1/responses")
|
||||
@@ -613,10 +636,10 @@ fn openai_cli_sync_plan_injects_auth_header_when_exact_headers_omit_it() {
|
||||
.expect("request");
|
||||
let (parts, _) = request.into_parts();
|
||||
|
||||
let mut payload = missing_exact_provider_request_payload("openai_cli_sync");
|
||||
let mut payload = missing_exact_provider_request_payload("openai_responses_sync");
|
||||
payload.provider_name = Some("openai".to_string());
|
||||
payload.provider_api_format = Some("openai:cli".to_string());
|
||||
payload.client_api_format = Some("openai:cli".to_string());
|
||||
payload.provider_api_format = Some("openai:responses".to_string());
|
||||
payload.client_api_format = Some("openai:responses".to_string());
|
||||
payload.model_name = Some("gpt-5".to_string());
|
||||
payload.upstream_url = Some("https://chatgpt.com/backend-api/codex/responses".to_string());
|
||||
payload.provider_request_headers =
|
||||
@@ -626,7 +649,7 @@ fn openai_cli_sync_plan_injects_auth_header_when_exact_headers_omit_it() {
|
||||
payload.provider_request_body = Some(json!({"model":"gpt-5"}));
|
||||
|
||||
let plan_and_report =
|
||||
build_openai_cli_sync_plan_from_decision(&parts, &json!({}), payload, false)
|
||||
build_openai_responses_sync_plan_from_decision(&parts, &json!({}), payload, false)
|
||||
.expect("builder should not error")
|
||||
.expect("plan should be built");
|
||||
|
||||
@@ -694,7 +717,7 @@ fn passthrough_sync_plan_uses_raw_body_bytes_when_decision_provides_base64_body(
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn openai_cli_stream_plan_injects_auth_header_when_exact_headers_omit_it() {
|
||||
fn openai_responses_stream_plan_injects_auth_header_when_exact_headers_omit_it() {
|
||||
let request = Request::builder()
|
||||
.method("POST")
|
||||
.uri("/v1/responses")
|
||||
@@ -702,10 +725,10 @@ fn openai_cli_stream_plan_injects_auth_header_when_exact_headers_omit_it() {
|
||||
.expect("request");
|
||||
let (parts, _) = request.into_parts();
|
||||
|
||||
let mut payload = missing_exact_provider_request_payload("openai_cli_stream");
|
||||
let mut payload = missing_exact_provider_request_payload("openai_responses_stream");
|
||||
payload.provider_name = Some("openai".to_string());
|
||||
payload.provider_api_format = Some("openai:cli".to_string());
|
||||
payload.client_api_format = Some("openai:cli".to_string());
|
||||
payload.provider_api_format = Some("openai:responses".to_string());
|
||||
payload.client_api_format = Some("openai:responses".to_string());
|
||||
payload.model_name = Some("gpt-5".to_string());
|
||||
payload.upstream_url = Some("https://chatgpt.com/backend-api/codex/responses".to_string());
|
||||
payload.provider_request_headers =
|
||||
@@ -715,7 +738,7 @@ fn openai_cli_stream_plan_injects_auth_header_when_exact_headers_omit_it() {
|
||||
payload.provider_request_body = Some(json!({"model":"gpt-5","stream":true}));
|
||||
|
||||
let plan_and_report =
|
||||
build_openai_cli_stream_plan_from_decision(&parts, &json!({}), payload, false)
|
||||
build_openai_responses_stream_plan_from_decision(&parts, &json!({}), payload, false)
|
||||
.expect("builder should not error")
|
||||
.expect("plan should be built");
|
||||
|
||||
@@ -739,9 +762,9 @@ fn openai_cli_stream_plan_injects_auth_header_when_exact_headers_omit_it() {
|
||||
|
||||
#[test]
|
||||
fn bypasses_execution_runtime_for_codex_backendapi_variant() {
|
||||
let mut payload = missing_exact_provider_request_payload("openai_cli_stream");
|
||||
payload.provider_api_format = Some("openai:cli".to_string());
|
||||
payload.client_api_format = Some("openai:cli".to_string());
|
||||
let mut payload = missing_exact_provider_request_payload("openai_responses_stream");
|
||||
payload.provider_api_format = Some("openai:responses".to_string());
|
||||
payload.client_api_format = Some("openai:responses".to_string());
|
||||
payload.upstream_url = Some("https://chatgpt.com/backendapi/codex/responses".to_string());
|
||||
|
||||
assert!(should_bypass_execution_runtime_decision(&payload));
|
||||
@@ -763,8 +786,8 @@ fn bypasses_execution_runtime_for_codex_plan_variant() {
|
||||
content_encoding: None,
|
||||
body: RequestBody::from_json(json!({"model":"gpt-5.4"})),
|
||||
stream: true,
|
||||
client_api_format: "openai:cli".to_string(),
|
||||
provider_api_format: "openai:cli".to_string(),
|
||||
client_api_format: "openai:responses".to_string(),
|
||||
provider_api_format: "openai:responses".to_string(),
|
||||
model_name: Some("gpt-5.4".to_string()),
|
||||
proxy: None,
|
||||
tls_profile: None,
|
||||
|
||||
Reference in New Issue
Block a user