mirror of
https://github.com/fawney19/Aether.git
synced 2026-10-04 08:27:46 +08:00
refactor: fold ai surfaces into formats
This commit is contained in:
Generated
+6
-17
@@ -45,9 +45,14 @@ dependencies = [
|
|||||||
name = "aether-ai-formats"
|
name = "aether-ai-formats"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"aether-contracts",
|
||||||
|
"base64 0.22.1",
|
||||||
|
"http",
|
||||||
"regex",
|
"regex",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
"sha1",
|
||||||
|
"sha2",
|
||||||
"uuid",
|
"uuid",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -56,7 +61,6 @@ name = "aether-ai-serving"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aether-ai-formats",
|
"aether-ai-formats",
|
||||||
"aether-ai-surfaces",
|
|
||||||
"aether-contracts",
|
"aether-contracts",
|
||||||
"aether-scheduler-core",
|
"aether-scheduler-core",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
@@ -67,21 +71,6 @@ dependencies = [
|
|||||||
"url",
|
"url",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "aether-ai-surfaces"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"aether-ai-formats",
|
|
||||||
"aether-contracts",
|
|
||||||
"base64 0.22.1",
|
|
||||||
"http",
|
|
||||||
"serde",
|
|
||||||
"serde_json",
|
|
||||||
"sha1",
|
|
||||||
"sha2",
|
|
||||||
"uuid",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aether-billing"
|
name = "aether-billing"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@@ -164,8 +153,8 @@ name = "aether-gateway"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aether-admin",
|
"aether-admin",
|
||||||
|
"aether-ai-formats",
|
||||||
"aether-ai-serving",
|
"aether-ai-serving",
|
||||||
"aether-ai-surfaces",
|
|
||||||
"aether-billing",
|
"aether-billing",
|
||||||
"aether-cache",
|
"aether-cache",
|
||||||
"aether-contracts",
|
"aether-contracts",
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ members = [
|
|||||||
"crates/aether-ai-formats",
|
"crates/aether-ai-formats",
|
||||||
"crates/aether-admin",
|
"crates/aether-admin",
|
||||||
"crates/aether-ai-serving",
|
"crates/aether-ai-serving",
|
||||||
"crates/aether-ai-surfaces",
|
|
||||||
"crates/aether-data-contracts",
|
"crates/aether-data-contracts",
|
||||||
"crates/aether-cache",
|
"crates/aether-cache",
|
||||||
"crates/aether-billing",
|
"crates/aether-billing",
|
||||||
@@ -34,7 +33,6 @@ repository = "https://github.com/fawney19/Aether.git"
|
|||||||
aether-admin = { path = "crates/aether-admin" }
|
aether-admin = { path = "crates/aether-admin" }
|
||||||
aether-ai-formats = { path = "crates/aether-ai-formats" }
|
aether-ai-formats = { path = "crates/aether-ai-formats" }
|
||||||
aether-ai-serving = { path = "crates/aether-ai-serving" }
|
aether-ai-serving = { path = "crates/aether-ai-serving" }
|
||||||
aether-ai-surfaces = { path = "crates/aether-ai-surfaces" }
|
|
||||||
aether-data-contracts = { path = "crates/aether-data-contracts" }
|
aether-data-contracts = { path = "crates/aether-data-contracts" }
|
||||||
aether-cache = { path = "crates/aether-cache" }
|
aether-cache = { path = "crates/aether-cache" }
|
||||||
aether-billing = { path = "crates/aether-billing" }
|
aether-billing = { path = "crates/aether-billing" }
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ description = "Rust ingress gateway for Aether phase 3a transparent proxy"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
aether-admin.workspace = true
|
aether-admin.workspace = true
|
||||||
|
aether-ai-formats.workspace = true
|
||||||
aether-ai-serving.workspace = true
|
aether-ai-serving.workspace = true
|
||||||
aether-ai-surfaces.workspace = true
|
|
||||||
aether-billing.workspace = true
|
aether-billing.workspace = true
|
||||||
aether-cache.workspace = true
|
aether-cache.workspace = true
|
||||||
aether-contracts.workspace = true
|
aether-contracts.workspace = true
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ pub(crate) use crate::ai_serving::{
|
|||||||
pub(crate) use crate::ai_serving::{
|
pub(crate) use crate::ai_serving::{
|
||||||
AiExecutionDecision, AiExecutionPlanPayload, AiStreamAttempt, AiSyncAttempt,
|
AiExecutionDecision, AiExecutionPlanPayload, AiStreamAttempt, AiSyncAttempt,
|
||||||
};
|
};
|
||||||
pub(crate) use aether_ai_surfaces::api::{
|
pub(crate) use aether_ai_formats::api::{
|
||||||
build_core_error_body_for_client_format, core_error_background_report_kind,
|
build_core_error_body_for_client_format, core_error_background_report_kind,
|
||||||
core_error_default_client_api_format, core_success_background_report_kind,
|
core_error_default_client_api_format, core_success_background_report_kind,
|
||||||
encode_kiro_sse_events, implicit_sync_finalize_report_kind, is_core_error_finalize_kind,
|
encode_kiro_sse_events, implicit_sync_finalize_report_kind, is_core_error_finalize_kind,
|
||||||
@@ -37,7 +37,7 @@ pub(crate) use aether_ai_surfaces::api::{
|
|||||||
resolve_claude_sync_spec, resolve_gemini_stream_spec, resolve_gemini_sync_spec,
|
resolve_claude_sync_spec, resolve_gemini_stream_spec, resolve_gemini_sync_spec,
|
||||||
resolve_local_image_stream_spec, resolve_local_image_sync_spec,
|
resolve_local_image_stream_spec, resolve_local_image_sync_spec,
|
||||||
resolve_local_same_format_stream_spec, resolve_local_same_format_sync_spec,
|
resolve_local_same_format_stream_spec, resolve_local_same_format_sync_spec,
|
||||||
ExecutionRuntimeAuthContext, GatewayControlPlanRequest, LocalCoreSyncErrorKind,
|
AiControlPlanRequest, ExecutionRuntimeAuthContext, LocalCoreSyncErrorKind,
|
||||||
LocalOpenAiImageSpec, LocalSameFormatProviderFamily, LocalSameFormatProviderSpec,
|
LocalOpenAiImageSpec, LocalSameFormatProviderFamily, LocalSameFormatProviderSpec,
|
||||||
LocalStandardSourceFamily, LocalStandardSourceMode, LocalStandardSpec,
|
LocalStandardSourceFamily, LocalStandardSourceMode, LocalStandardSpec,
|
||||||
StreamingStandardTerminalObserver, EXECUTION_RUNTIME_STREAM_DECISION_ACTION,
|
StreamingStandardTerminalObserver, EXECUTION_RUNTIME_STREAM_DECISION_ACTION,
|
||||||
@@ -52,7 +52,7 @@ pub(crate) fn parse_direct_request_body(
|
|||||||
parts: &http::request::Parts,
|
parts: &http::request::Parts,
|
||||||
body_bytes: &axum::body::Bytes,
|
body_bytes: &axum::body::Bytes,
|
||||||
) -> Option<(serde_json::Value, Option<String>)> {
|
) -> Option<(serde_json::Value, Option<String>)> {
|
||||||
aether_ai_surfaces::api::parse_direct_request_body(
|
aether_ai_formats::api::parse_direct_request_body(
|
||||||
is_json_request(&parts.headers),
|
is_json_request(&parts.headers),
|
||||||
body_bytes.as_ref(),
|
body_bytes.as_ref(),
|
||||||
)
|
)
|
||||||
@@ -62,7 +62,7 @@ pub(crate) fn resolve_execution_runtime_stream_plan_kind(
|
|||||||
parts: &http::request::Parts,
|
parts: &http::request::Parts,
|
||||||
decision: &GatewayControlDecision,
|
decision: &GatewayControlDecision,
|
||||||
) -> Option<&'static str> {
|
) -> Option<&'static str> {
|
||||||
aether_ai_surfaces::api::resolve_execution_runtime_stream_plan_kind(
|
aether_ai_formats::api::resolve_execution_runtime_stream_plan_kind(
|
||||||
decision.route_class.as_deref(),
|
decision.route_class.as_deref(),
|
||||||
decision.route_family.as_deref(),
|
decision.route_family.as_deref(),
|
||||||
decision.route_kind.as_deref(),
|
decision.route_kind.as_deref(),
|
||||||
@@ -75,7 +75,7 @@ pub(crate) fn resolve_execution_runtime_sync_plan_kind(
|
|||||||
parts: &http::request::Parts,
|
parts: &http::request::Parts,
|
||||||
decision: &GatewayControlDecision,
|
decision: &GatewayControlDecision,
|
||||||
) -> Option<&'static str> {
|
) -> Option<&'static str> {
|
||||||
aether_ai_surfaces::api::resolve_execution_runtime_sync_plan_kind(
|
aether_ai_formats::api::resolve_execution_runtime_sync_plan_kind(
|
||||||
decision.route_class.as_deref(),
|
decision.route_class.as_deref(),
|
||||||
decision.route_family.as_deref(),
|
decision.route_family.as_deref(),
|
||||||
decision.route_kind.as_deref(),
|
decision.route_kind.as_deref(),
|
||||||
@@ -93,28 +93,28 @@ pub(crate) fn is_matching_stream_request(
|
|||||||
crate::ai_serving::planner_is_matching_stream_request(plan_kind, parts, body_json, body_base64)
|
crate::ai_serving::planner_is_matching_stream_request(plan_kind, parts, body_json, body_base64)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn supports_sync_scheduler_decision_kind(plan_kind: &str) -> bool {
|
pub(crate) fn supports_sync_execution_decision_kind(plan_kind: &str) -> bool {
|
||||||
aether_ai_surfaces::api::supports_sync_scheduler_decision_kind(plan_kind)
|
aether_ai_formats::api::supports_sync_execution_decision_kind(plan_kind)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn supports_stream_scheduler_decision_kind(plan_kind: &str) -> bool {
|
pub(crate) fn supports_stream_execution_decision_kind(plan_kind: &str) -> bool {
|
||||||
aether_ai_surfaces::api::supports_stream_scheduler_decision_kind(plan_kind)
|
aether_ai_formats::api::supports_stream_execution_decision_kind(plan_kind)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn aggregate_openai_chat_stream_sync_response(body: &[u8]) -> Option<serde_json::Value> {
|
pub(crate) fn aggregate_openai_chat_stream_sync_response(body: &[u8]) -> Option<serde_json::Value> {
|
||||||
aether_ai_surfaces::api::aggregate_openai_chat_stream_sync_response(body)
|
aether_ai_formats::api::aggregate_openai_chat_stream_sync_response(body)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn aggregate_openai_responses_stream_sync_response(
|
pub(crate) fn aggregate_openai_responses_stream_sync_response(
|
||||||
body: &[u8],
|
body: &[u8],
|
||||||
) -> Option<serde_json::Value> {
|
) -> Option<serde_json::Value> {
|
||||||
aether_ai_surfaces::api::aggregate_openai_responses_stream_sync_response(body)
|
aether_ai_formats::api::aggregate_openai_responses_stream_sync_response(body)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn aggregate_claude_stream_sync_response(body: &[u8]) -> Option<serde_json::Value> {
|
pub(crate) fn aggregate_claude_stream_sync_response(body: &[u8]) -> Option<serde_json::Value> {
|
||||||
aether_ai_surfaces::api::aggregate_claude_stream_sync_response(body)
|
aether_ai_formats::api::aggregate_claude_stream_sync_response(body)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn aggregate_gemini_stream_sync_response(body: &[u8]) -> Option<serde_json::Value> {
|
pub(crate) fn aggregate_gemini_stream_sync_response(body: &[u8]) -> Option<serde_json::Value> {
|
||||||
aether_ai_surfaces::api::aggregate_gemini_stream_sync_response(body)
|
aether_ai_formats::api::aggregate_gemini_stream_sync_response(body)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ use crate::ai_serving::{
|
|||||||
is_matching_stream_http_request as is_matching_stream_http_request_impl,
|
is_matching_stream_http_request as is_matching_stream_http_request_impl,
|
||||||
resolve_execution_runtime_stream_plan_kind as resolve_execution_runtime_stream_plan_kind_impl,
|
resolve_execution_runtime_stream_plan_kind as resolve_execution_runtime_stream_plan_kind_impl,
|
||||||
resolve_execution_runtime_sync_plan_kind as resolve_execution_runtime_sync_plan_kind_impl,
|
resolve_execution_runtime_sync_plan_kind as resolve_execution_runtime_sync_plan_kind_impl,
|
||||||
supports_stream_scheduler_decision_kind as supports_stream_scheduler_decision_kind_impl,
|
supports_stream_execution_decision_kind as supports_stream_execution_decision_kind_impl,
|
||||||
supports_sync_scheduler_decision_kind as supports_sync_scheduler_decision_kind_impl,
|
supports_sync_execution_decision_kind as supports_sync_execution_decision_kind_impl,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(crate) fn resolve_execution_runtime_stream_plan_kind(
|
pub(crate) fn resolve_execution_runtime_stream_plan_kind(
|
||||||
@@ -42,12 +42,12 @@ pub(crate) fn is_matching_stream_request(
|
|||||||
is_matching_stream_http_request_impl(plan_kind, parts, body_json, body_base64)
|
is_matching_stream_http_request_impl(plan_kind, parts, body_json, body_base64)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn supports_sync_scheduler_decision_kind(plan_kind: &str) -> bool {
|
pub(crate) fn supports_sync_execution_decision_kind(plan_kind: &str) -> bool {
|
||||||
supports_sync_scheduler_decision_kind_impl(plan_kind)
|
supports_sync_execution_decision_kind_impl(plan_kind)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn supports_stream_scheduler_decision_kind(plan_kind: &str) -> bool {
|
pub(crate) fn supports_stream_execution_decision_kind(plan_kind: &str) -> bool {
|
||||||
supports_stream_scheduler_decision_kind_impl(plan_kind)
|
supports_stream_execution_decision_kind_impl(plan_kind)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@@ -57,8 +57,8 @@ mod tests {
|
|||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
is_matching_stream_request, resolve_execution_runtime_stream_plan_kind,
|
is_matching_stream_request, resolve_execution_runtime_stream_plan_kind,
|
||||||
resolve_execution_runtime_sync_plan_kind, supports_stream_scheduler_decision_kind,
|
resolve_execution_runtime_sync_plan_kind, supports_stream_execution_decision_kind,
|
||||||
supports_sync_scheduler_decision_kind,
|
supports_sync_execution_decision_kind,
|
||||||
};
|
};
|
||||||
use crate::ai_serving::GatewayControlDecision;
|
use crate::ai_serving::GatewayControlDecision;
|
||||||
|
|
||||||
@@ -78,7 +78,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn resolves_openai_chat_plan_kinds_via_surface_crate() {
|
fn resolves_openai_chat_plan_kinds_via_format_crate() {
|
||||||
let request = Request::builder()
|
let request = Request::builder()
|
||||||
.method(Method::POST)
|
.method(Method::POST)
|
||||||
.uri("/v1/chat/completions")
|
.uri("/v1/chat/completions")
|
||||||
@@ -118,8 +118,8 @@ mod tests {
|
|||||||
&serde_json::json!({"stream": true}),
|
&serde_json::json!({"stream": true}),
|
||||||
None,
|
None,
|
||||||
));
|
));
|
||||||
assert!(supports_sync_scheduler_decision_kind("openai_chat_sync"));
|
assert!(supports_sync_execution_decision_kind("openai_chat_sync"));
|
||||||
assert!(supports_stream_scheduler_decision_kind(
|
assert!(supports_stream_execution_decision_kind(
|
||||||
"openai_chat_stream"
|
"openai_chat_stream"
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
pub(crate) use aether_ai_surfaces::api::{
|
pub(crate) use aether_ai_formats::api::{
|
||||||
aggregate_claude_stream_sync_response, aggregate_gemini_stream_sync_response,
|
aggregate_claude_stream_sync_response, aggregate_gemini_stream_sync_response,
|
||||||
aggregate_openai_chat_stream_sync_response, aggregate_openai_responses_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,
|
aggregate_standard_chat_stream_sync_response, aggregate_standard_cli_stream_sync_response,
|
||||||
@@ -62,11 +62,11 @@ pub(crate) use aether_ai_surfaces::api::{
|
|||||||
resolve_local_video_sync_spec, resolve_openai_chat_max_tokens,
|
resolve_local_video_sync_spec, resolve_openai_chat_max_tokens,
|
||||||
resolve_openai_responses_stream_spec, resolve_openai_responses_sync_spec,
|
resolve_openai_responses_stream_spec, resolve_openai_responses_sync_spec,
|
||||||
resolve_requested_openai_image_model_for_request, stream_body_contains_error_event,
|
resolve_requested_openai_image_model_for_request, stream_body_contains_error_event,
|
||||||
supports_stream_scheduler_decision_kind, supports_sync_scheduler_decision_kind,
|
supports_stream_execution_decision_kind, supports_sync_execution_decision_kind,
|
||||||
sync_chat_response_conversion_kind, sync_cli_response_conversion_kind,
|
sync_chat_response_conversion_kind, sync_cli_response_conversion_kind,
|
||||||
transform_provider_private_stream_line, value_as_u64, AiSurfaceFinalizeError,
|
transform_provider_private_stream_line, value_as_u64, AiControlPlanRequest,
|
||||||
AiSurfaceStreamRewriter, CanonicalStreamFrame, ClaudeClientEmitter, ClaudeProviderState,
|
AiSurfaceFinalizeError, AiSurfaceStreamRewriter, CanonicalStreamFrame, ClaudeClientEmitter,
|
||||||
ExecutionRuntimeAuthContext, FinalizeStreamRewriteMode, GatewayControlPlanRequest,
|
ClaudeProviderState, ExecutionRuntimeAuthContext, FinalizeStreamRewriteMode,
|
||||||
GeminiClientEmitter, GeminiProviderState, KiroToClaudeCliStreamState, LocalCoreSyncErrorKind,
|
GeminiClientEmitter, GeminiProviderState, KiroToClaudeCliStreamState, LocalCoreSyncErrorKind,
|
||||||
LocalGeminiFilesSpec, LocalOpenAiImageSpec, LocalOpenAiResponsesSpec,
|
LocalGeminiFilesSpec, LocalOpenAiImageSpec, LocalOpenAiResponsesSpec,
|
||||||
LocalSameFormatProviderFamily, LocalSameFormatProviderSpec, LocalStandardSourceFamily,
|
LocalSameFormatProviderFamily, LocalSameFormatProviderSpec, LocalStandardSourceFamily,
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ use std::collections::BTreeMap;
|
|||||||
|
|
||||||
use crate::ai_serving::api::{
|
use crate::ai_serving::api::{
|
||||||
is_matching_stream_request, resolve_execution_runtime_stream_plan_kind,
|
is_matching_stream_request, resolve_execution_runtime_stream_plan_kind,
|
||||||
supports_stream_scheduler_decision_kind, AiStreamAttempt, OPENAI_VIDEO_CONTENT_PLAN_KIND,
|
supports_stream_execution_decision_kind, AiStreamAttempt, OPENAI_VIDEO_CONTENT_PLAN_KIND,
|
||||||
};
|
};
|
||||||
use crate::api::response::build_client_response_from_parts;
|
use crate::api::response::build_client_response_from_parts;
|
||||||
use crate::control::GatewayControlDecision;
|
use crate::control::GatewayControlDecision;
|
||||||
@@ -60,7 +60,7 @@ pub(crate) async fn maybe_execute_via_stream_decision_path(
|
|||||||
body_base64,
|
body_base64,
|
||||||
plan_kind,
|
plan_kind,
|
||||||
bypass_cache_key,
|
bypass_cache_key,
|
||||||
scheduler_supported: supports_stream_scheduler_decision_kind(plan_kind),
|
scheduler_supported: supports_stream_execution_decision_kind(plan_kind),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(from_ai_serving_outcome(
|
Ok(from_ai_serving_outcome(
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ use std::collections::BTreeMap;
|
|||||||
|
|
||||||
use crate::ai_serving::api::{
|
use crate::ai_serving::api::{
|
||||||
is_matching_stream_request, resolve_execution_runtime_stream_plan_kind,
|
is_matching_stream_request, resolve_execution_runtime_stream_plan_kind,
|
||||||
resolve_execution_runtime_sync_plan_kind, supports_sync_scheduler_decision_kind, AiSyncAttempt,
|
resolve_execution_runtime_sync_plan_kind, supports_sync_execution_decision_kind, AiSyncAttempt,
|
||||||
GEMINI_VIDEO_CANCEL_SYNC_PLAN_KIND, OPENAI_VIDEO_CANCEL_SYNC_PLAN_KIND,
|
GEMINI_VIDEO_CANCEL_SYNC_PLAN_KIND, OPENAI_VIDEO_CANCEL_SYNC_PLAN_KIND,
|
||||||
OPENAI_VIDEO_DELETE_SYNC_PLAN_KIND, OPENAI_VIDEO_REMIX_SYNC_PLAN_KIND,
|
OPENAI_VIDEO_DELETE_SYNC_PLAN_KIND, OPENAI_VIDEO_REMIX_SYNC_PLAN_KIND,
|
||||||
};
|
};
|
||||||
@@ -72,7 +72,7 @@ pub(crate) async fn maybe_execute_via_sync_decision_path(
|
|||||||
body_is_empty: body_bytes.is_empty(),
|
body_is_empty: body_bytes.is_empty(),
|
||||||
plan_kind,
|
plan_kind,
|
||||||
bypass_cache_key,
|
bypass_cache_key,
|
||||||
scheduler_supported: supports_sync_scheduler_decision_kind(plan_kind),
|
scheduler_supported: supports_sync_execution_decision_kind(plan_kind),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(from_ai_serving_outcome(
|
Ok(from_ai_serving_outcome(
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ mod video_tasks;
|
|||||||
mod wallet_runtime;
|
mod wallet_runtime;
|
||||||
|
|
||||||
pub(crate) use self::ai_serving::api::{
|
pub(crate) use self::ai_serving::api::{
|
||||||
GatewayControlPlanRequest, EXECUTION_RUNTIME_STREAM_DECISION_ACTION,
|
AiControlPlanRequest, EXECUTION_RUNTIME_STREAM_DECISION_ACTION,
|
||||||
EXECUTION_RUNTIME_SYNC_DECISION_ACTION, GEMINI_FILES_DOWNLOAD_PLAN_KIND,
|
EXECUTION_RUNTIME_SYNC_DECISION_ACTION, GEMINI_FILES_DOWNLOAD_PLAN_KIND,
|
||||||
OPENAI_VIDEO_CONTENT_PLAN_KIND,
|
OPENAI_VIDEO_CONTENT_PLAN_KIND,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -688,26 +688,30 @@ fn crate_root_exposes_real_admin_and_ai_serving_facades() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn gateway_ai_serving_api_module_delegates_pure_ownership_to_surface_crate() {
|
fn gateway_ai_serving_api_module_delegates_pure_ownership_to_format_crate() {
|
||||||
let gateway_api = read_workspace_file("apps/aether-gateway/src/ai_serving/api.rs");
|
let gateway_api = read_workspace_file("apps/aether-gateway/src/ai_serving/api.rs");
|
||||||
assert!(
|
assert!(
|
||||||
gateway_api.contains("pub(crate) use aether_ai_surfaces::api::{"),
|
gateway_api.contains("pub(crate) use aether_ai_formats::api::{"),
|
||||||
"ai_serving/api.rs should re-export pure ownership through aether_ai_surfaces::api"
|
"ai_serving/api.rs should re-export pure ownership through aether_ai_formats::api"
|
||||||
);
|
);
|
||||||
|
|
||||||
let surface_crate_api = read_workspace_file("crates/aether-ai-surfaces/src/api.rs");
|
let format_crate_api = read_workspace_file("crates/aether-ai-formats/src/api.rs");
|
||||||
for pattern in [
|
for pattern in [
|
||||||
"pub use crate::contracts::{",
|
"pub use crate::contracts::{",
|
||||||
|
"pub use crate::provider_compat::kiro_stream::{",
|
||||||
|
"pub use crate::provider_compat::private_envelope::{",
|
||||||
|
"pub use crate::provider_compat::surfaces::{",
|
||||||
|
"pub use crate::request::common::{",
|
||||||
|
"pub use crate::request::route::{",
|
||||||
|
"pub use crate::response::common::{",
|
||||||
|
"pub use crate::response::error_body::{",
|
||||||
"pub use aether_ai_formats::{",
|
"pub use aether_ai_formats::{",
|
||||||
"pub use aether_ai_formats::conversion::request::{",
|
"pub use aether_ai_formats::protocol::conversion::request::{",
|
||||||
"pub use aether_ai_formats::conversion::response::{",
|
"pub use aether_ai_formats::protocol::conversion::response::{",
|
||||||
"pub use crate::finalize::error_body::{",
|
|
||||||
"pub use crate::planner::common::{",
|
|
||||||
"pub use crate::planner::route::{",
|
|
||||||
] {
|
] {
|
||||||
assert!(
|
assert!(
|
||||||
surface_crate_api.contains(pattern),
|
format_crate_api.contains(pattern),
|
||||||
"aether-ai-surfaces/src/api.rs should expose crate facade seam {pattern}"
|
"aether-ai-formats/src/api.rs should expose crate facade seam {pattern}"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ fn ai_serving_target_structure_removes_legacy_pipeline_boundary() {
|
|||||||
for root in [
|
for root in [
|
||||||
"apps/aether-gateway/src",
|
"apps/aether-gateway/src",
|
||||||
"crates/aether-ai-serving/src",
|
"crates/aether-ai-serving/src",
|
||||||
"crates/aether-ai-surfaces/src",
|
"crates/aether-ai-formats/src",
|
||||||
] {
|
] {
|
||||||
for file in collect_workspace_rust_files(root) {
|
for file in collect_workspace_rust_files(root) {
|
||||||
let relative = file
|
let relative = file
|
||||||
@@ -526,7 +526,7 @@ fn ai_serving_internal_dtos_use_ai_execution_names() {
|
|||||||
"apps/aether-gateway/src/executor",
|
"apps/aether-gateway/src/executor",
|
||||||
"apps/aether-gateway/src/execution_runtime",
|
"apps/aether-gateway/src/execution_runtime",
|
||||||
"crates/aether-ai-serving/src",
|
"crates/aether-ai-serving/src",
|
||||||
"crates/aether-ai-surfaces/src",
|
"crates/aether-ai-formats/src",
|
||||||
] {
|
] {
|
||||||
for file in collect_workspace_rust_files(root) {
|
for file in collect_workspace_rust_files(root) {
|
||||||
let relative = file
|
let relative = file
|
||||||
@@ -559,11 +559,8 @@ fn ai_serving_internal_dtos_use_ai_execution_names() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ai_surface_and_format_crates_stay_free_of_gateway_runtime_deps() {
|
fn ai_format_crate_stays_free_of_gateway_runtime_deps() {
|
||||||
for manifest_path in [
|
for manifest_path in ["crates/aether-ai-formats/Cargo.toml"] {
|
||||||
"crates/aether-ai-surfaces/Cargo.toml",
|
|
||||||
"crates/aether-ai-formats/Cargo.toml",
|
|
||||||
] {
|
|
||||||
let manifest = read_workspace_file(manifest_path);
|
let manifest = read_workspace_file(manifest_path);
|
||||||
for forbidden in [
|
for forbidden in [
|
||||||
"axum",
|
"axum",
|
||||||
@@ -581,10 +578,7 @@ fn ai_surface_and_format_crates_stay_free_of_gateway_runtime_deps() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut violations = Vec::new();
|
let mut violations = Vec::new();
|
||||||
for root in [
|
for root in ["crates/aether-ai-formats/src"] {
|
||||||
"crates/aether-ai-surfaces/src",
|
|
||||||
"crates/aether-ai-formats/src",
|
|
||||||
] {
|
|
||||||
for file in collect_workspace_rust_files(root) {
|
for file in collect_workspace_rust_files(root) {
|
||||||
let source = std::fs::read_to_string(&file).expect("source file should be readable");
|
let source = std::fs::read_to_string(&file).expect("source file should be readable");
|
||||||
let hits = [
|
let hits = [
|
||||||
@@ -607,7 +601,7 @@ fn ai_surface_and_format_crates_stay_free_of_gateway_runtime_deps() {
|
|||||||
}
|
}
|
||||||
assert!(
|
assert!(
|
||||||
violations.is_empty(),
|
violations.is_empty(),
|
||||||
"surface and format crates should stay pure of gateway runtime dependencies:\n{}",
|
"format crate should stay pure of gateway runtime dependencies:\n{}",
|
||||||
violations.join("\n")
|
violations.join("\n")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -617,7 +611,6 @@ fn aether_runtime_stays_free_of_ai_serving_policy() {
|
|||||||
let runtime_manifest = read_workspace_file("crates/aether-runtime/Cargo.toml");
|
let runtime_manifest = read_workspace_file("crates/aether-runtime/Cargo.toml");
|
||||||
for forbidden in [
|
for forbidden in [
|
||||||
"aether-ai-serving",
|
"aether-ai-serving",
|
||||||
"aether-ai-surfaces",
|
|
||||||
"aether-ai-formats",
|
"aether-ai-formats",
|
||||||
"aether-provider-transport",
|
"aether-provider-transport",
|
||||||
"aether-gateway",
|
"aether-gateway",
|
||||||
@@ -633,7 +626,6 @@ fn aether_runtime_stays_free_of_ai_serving_policy() {
|
|||||||
let source = std::fs::read_to_string(&file).expect("source file should be readable");
|
let source = std::fs::read_to_string(&file).expect("source file should be readable");
|
||||||
let hits = [
|
let hits = [
|
||||||
"aether_ai_serving",
|
"aether_ai_serving",
|
||||||
"aether_ai_surfaces",
|
|
||||||
"aether_ai_formats",
|
"aether_ai_formats",
|
||||||
"aether_provider_transport",
|
"aether_provider_transport",
|
||||||
"AiExecution",
|
"AiExecution",
|
||||||
@@ -687,14 +679,14 @@ fn ai_serving_crate_api_is_confined_to_root_seams() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let source = std::fs::read_to_string(&file).expect("source file should be readable");
|
let source = std::fs::read_to_string(&file).expect("source file should be readable");
|
||||||
if source.contains("aether_ai_surfaces::api") {
|
if source.contains("aether_ai_formats::api") {
|
||||||
violations.push(relative);
|
violations.push(relative);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
violations.is_empty(),
|
violations.is_empty(),
|
||||||
"gateway code should only depend on aether_ai_surfaces::api through ai_serving/pure/mod.rs or ai_serving/api.rs:\n{}",
|
"gateway code should only depend on aether_ai_formats::api through ai_serving/pure/mod.rs or ai_serving/api.rs:\n{}",
|
||||||
violations.join("\n")
|
violations.join("\n")
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -718,14 +710,14 @@ fn ai_serving_crate_api_is_confined_to_root_seams() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let source = std::fs::read_to_string(&file).expect("source file should be readable");
|
let source = std::fs::read_to_string(&file).expect("source file should be readable");
|
||||||
if source.contains("aether_ai_surfaces::") {
|
if source.contains("aether_ai_formats::") {
|
||||||
crate_violations.push(relative);
|
crate_violations.push(relative);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
crate_violations.is_empty(),
|
crate_violations.is_empty(),
|
||||||
"gateway code should only depend directly on aether_ai_surfaces through ai_serving root seams:\n{}",
|
"gateway code should only depend directly on aether_ai_formats through ai_serving root seams:\n{}",
|
||||||
crate_violations.join("\n")
|
crate_violations.join("\n")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -766,7 +758,7 @@ fn ai_serving_routes_control_and_execution_deps_through_facades() {
|
|||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
!workspace_file_exists("apps/aether-gateway/src/ai_serving/contracts"),
|
!workspace_file_exists("apps/aether-gateway/src/ai_serving/contracts"),
|
||||||
"gateway ai_serving should not keep a contracts directory; contracts belong to aether-ai-surfaces and serving DTOs belong to aether-ai-serving"
|
"gateway ai_serving should not keep a contracts directory; contracts belong to aether-ai-formats and serving DTOs belong to aether-ai-serving"
|
||||||
);
|
);
|
||||||
|
|
||||||
let ai_serving_mod = read_workspace_file("apps/aether-gateway/src/ai_serving/mod.rs");
|
let ai_serving_mod = read_workspace_file("apps/aether-gateway/src/ai_serving/mod.rs");
|
||||||
@@ -775,7 +767,7 @@ fn ai_serving_routes_control_and_execution_deps_through_facades() {
|
|||||||
"ai_serving/mod.rs should not own GatewayControlAuthContext after execution auth DTO extraction"
|
"ai_serving/mod.rs should not own GatewayControlAuthContext after execution auth DTO extraction"
|
||||||
);
|
);
|
||||||
for pattern in [
|
for pattern in [
|
||||||
"struct GatewayControlPlanRequest",
|
"struct AiControlPlanRequest",
|
||||||
"struct AiExecutionPlanPayload",
|
"struct AiExecutionPlanPayload",
|
||||||
"struct AiExecutionDecision",
|
"struct AiExecutionDecision",
|
||||||
] {
|
] {
|
||||||
@@ -795,8 +787,8 @@ fn ai_serving_routes_control_and_execution_deps_through_facades() {
|
|||||||
"ai_serving/mod.rs should delegate exact-request detection through aether-ai-serving"
|
"ai_serving/mod.rs should delegate exact-request detection through aether-ai-serving"
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
!ai_serving_mod.contains("GatewayControlPlanRequest {"),
|
!ai_serving_mod.contains("AiControlPlanRequest {"),
|
||||||
"ai_serving/mod.rs should not locally construct GatewayControlPlanRequest after helper extraction"
|
"ai_serving/mod.rs should not locally construct AiControlPlanRequest after helper extraction"
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
!ai_serving_mod.contains("pub(crate) async fn build_gateway_plan_request("),
|
!ai_serving_mod.contains("pub(crate) async fn build_gateway_plan_request("),
|
||||||
@@ -881,17 +873,17 @@ fn ai_serving_routes_control_and_execution_deps_through_facades() {
|
|||||||
assert!(
|
assert!(
|
||||||
gateway_finalize_common
|
gateway_finalize_common
|
||||||
.contains("prepare_local_success_response_parts as prepare_local_success_response_parts_impl"),
|
.contains("prepare_local_success_response_parts as prepare_local_success_response_parts_impl"),
|
||||||
"finalize/common.rs should delegate success response-part normalization to the surface crate"
|
"finalize/common.rs should delegate success response-part normalization to the format crate"
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
gateway_finalize_common
|
gateway_finalize_common
|
||||||
.contains("build_local_success_background_report as build_local_success_background_report_impl"),
|
.contains("build_local_success_background_report as build_local_success_background_report_impl"),
|
||||||
"finalize/common.rs should delegate pure success background-report construction to the surface crate"
|
"finalize/common.rs should delegate pure success background-report construction to the format crate"
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
gateway_finalize_common
|
gateway_finalize_common
|
||||||
.contains("build_local_success_conversion_background_report as build_local_success_conversion_background_report_impl"),
|
.contains("build_local_success_conversion_background_report as build_local_success_conversion_background_report_impl"),
|
||||||
"finalize/common.rs should delegate pure conversion success background-report construction to the surface crate"
|
"finalize/common.rs should delegate pure conversion success background-report construction to the format crate"
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
gateway_finalize_common.contains("surface_report_parts_from_gateway(")
|
gateway_finalize_common.contains("surface_report_parts_from_gateway(")
|
||||||
@@ -930,7 +922,7 @@ fn ai_serving_routes_control_and_execution_deps_through_facades() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
!ai_serving_mod.contains("pub(crate) use aether_ai_surfaces::api::*;"),
|
!ai_serving_mod.contains("pub(crate) use aether_ai_formats::api::*;"),
|
||||||
"ai_serving/mod.rs should not keep wildcard surface-crate exports after root-seam freeze"
|
"ai_serving/mod.rs should not keep wildcard surface-crate exports after root-seam freeze"
|
||||||
);
|
);
|
||||||
for export in [
|
for export in [
|
||||||
@@ -968,7 +960,7 @@ fn ai_serving_routes_control_and_execution_deps_through_facades() {
|
|||||||
|
|
||||||
let pure_mod = read_workspace_file("apps/aether-gateway/src/ai_serving/pure/mod.rs");
|
let pure_mod = read_workspace_file("apps/aether-gateway/src/ai_serving/pure/mod.rs");
|
||||||
for pattern in [
|
for pattern in [
|
||||||
"pub(crate) use aether_ai_surfaces::api::{",
|
"pub(crate) use aether_ai_formats::api::{",
|
||||||
"ExecutionRuntimeAuthContext",
|
"ExecutionRuntimeAuthContext",
|
||||||
"ProviderAdaptationDescriptor",
|
"ProviderAdaptationDescriptor",
|
||||||
"RequestConversionKind",
|
"RequestConversionKind",
|
||||||
@@ -1017,8 +1009,8 @@ fn ai_serving_routes_provider_transport_deps_through_facade() {
|
|||||||
"ai_serving/runtime should stay removed after facade cleanup"
|
"ai_serving/runtime should stay removed after facade cleanup"
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
!workspace_file_exists("crates/aether-ai-surfaces/src/transport.rs"),
|
!workspace_file_exists("crates/aether-ai-formats/src/transport.rs"),
|
||||||
"aether-ai-surfaces should not expose a provider transport bridge"
|
"aether-ai-formats should not expose a provider transport bridge"
|
||||||
);
|
);
|
||||||
|
|
||||||
let provider_transport_facade =
|
let provider_transport_facade =
|
||||||
@@ -1039,7 +1031,7 @@ fn ai_serving_routes_provider_transport_deps_through_facade() {
|
|||||||
"crate::provider_transport::url",
|
"crate::provider_transport::url",
|
||||||
"crate::provider_transport::policy",
|
"crate::provider_transport::policy",
|
||||||
"crate::provider_transport::snapshot",
|
"crate::provider_transport::snapshot",
|
||||||
"aether_ai_surfaces::transport",
|
"aether_ai_formats::transport",
|
||||||
] {
|
] {
|
||||||
assert!(
|
assert!(
|
||||||
!provider_transport_facade.contains(forbidden),
|
!provider_transport_facade.contains(forbidden),
|
||||||
@@ -2161,7 +2153,7 @@ fn ai_serving_image_routes_split_surface_normalization_and_transport_policy() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let surface_image =
|
let surface_image =
|
||||||
read_workspace_file("crates/aether-ai-surfaces/src/planner/specialized/image.rs");
|
read_workspace_file("crates/aether-ai-formats/src/request/specialized/image.rs");
|
||||||
for pattern in [
|
for pattern in [
|
||||||
"pub enum OpenAiImageOperation",
|
"pub enum OpenAiImageOperation",
|
||||||
"pub fn is_openai_image_stream_request(",
|
"pub fn is_openai_image_stream_request(",
|
||||||
@@ -2172,7 +2164,7 @@ fn ai_serving_image_routes_split_surface_normalization_and_transport_policy() {
|
|||||||
] {
|
] {
|
||||||
assert!(
|
assert!(
|
||||||
surface_image.contains(pattern),
|
surface_image.contains(pattern),
|
||||||
"aether-ai-surfaces specialized/image.rs should own OpenAI image surface logic {pattern}"
|
"aether-ai-formats specialized/image.rs should own OpenAI image format surface logic {pattern}"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3214,7 +3206,7 @@ fn ai_serving_leaf_planner_owners_route_contract_specs_through_gateway_seams() {
|
|||||||
] {
|
] {
|
||||||
let source = read_workspace_file(path);
|
let source = read_workspace_file(path);
|
||||||
assert!(
|
assert!(
|
||||||
!source.contains("aether_ai_surfaces::contracts::ExecutionRuntimeAuthContext"),
|
!source.contains("aether_ai_formats::contracts::ExecutionRuntimeAuthContext"),
|
||||||
"{path} should consume ExecutionRuntimeAuthContext through gateway ai_serving seams"
|
"{path} should consume ExecutionRuntimeAuthContext through gateway ai_serving seams"
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
@@ -3228,7 +3220,7 @@ fn ai_serving_leaf_planner_owners_route_contract_specs_through_gateway_seams() {
|
|||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
!specialized_files_decision
|
!specialized_files_decision
|
||||||
.contains("aether_ai_surfaces::planner::specialized::files::LocalGeminiFilesSpec"),
|
.contains("aether_ai_formats::request::specialized::files::LocalGeminiFilesSpec"),
|
||||||
"planner/specialized/files/decision.rs should consume LocalGeminiFilesSpec through the local specialized seam"
|
"planner/specialized/files/decision.rs should consume LocalGeminiFilesSpec through the local specialized seam"
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
@@ -3246,16 +3238,16 @@ fn ai_serving_leaf_planner_owners_route_contract_specs_through_gateway_seams() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ai_serving_m5_moves_contracts_and_route_logic_into_surface_crate() {
|
fn ai_serving_m5_moves_contracts_and_route_logic_into_format_crate() {
|
||||||
for path in [
|
for path in [
|
||||||
"crates/aether-ai-surfaces/src/contracts/actions.rs",
|
"crates/aether-ai-formats/src/contracts/actions.rs",
|
||||||
"crates/aether-ai-surfaces/src/contracts/plan_kinds.rs",
|
"crates/aether-ai-formats/src/contracts/plan_kinds.rs",
|
||||||
"crates/aether-ai-surfaces/src/contracts/report_kinds.rs",
|
"crates/aether-ai-formats/src/contracts/report_kinds.rs",
|
||||||
"crates/aether-ai-surfaces/src/planner/route.rs",
|
"crates/aether-ai-formats/src/request/route.rs",
|
||||||
] {
|
] {
|
||||||
assert!(
|
assert!(
|
||||||
workspace_file_exists(path),
|
workspace_file_exists(path),
|
||||||
"{path} should exist after initial surface crate extraction"
|
"{path} should exist after initial format crate extraction"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3288,7 +3280,7 @@ fn ai_serving_m5_moves_contracts_and_route_logic_into_surface_crate() {
|
|||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
gateway_route_runtime.contains("is_matching_stream_http_request"),
|
gateway_route_runtime.contains("is_matching_stream_http_request"),
|
||||||
"planner/route.rs should delegate full HTTP stream matching to aether-ai-surfaces"
|
"planner/route.rs should delegate full HTTP stream matching to aether-ai-formats"
|
||||||
);
|
);
|
||||||
for legacy_literal in [
|
for legacy_literal in [
|
||||||
"\"openai_chat_stream\"",
|
"\"openai_chat_stream\"",
|
||||||
@@ -3312,14 +3304,14 @@ fn ai_serving_m5_moves_contracts_and_route_logic_into_surface_crate() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let surface_route = read_workspace_file("crates/aether-ai-surfaces/src/planner/route.rs");
|
let surface_route = read_workspace_file("crates/aether-ai-formats/src/request/route.rs");
|
||||||
for pattern in [
|
for pattern in [
|
||||||
"pub fn is_matching_stream_http_request(",
|
"pub fn is_matching_stream_http_request(",
|
||||||
"is_openai_image_stream_request(parts, body_json, body_base64)",
|
"is_openai_image_stream_request(parts, body_json, body_base64)",
|
||||||
] {
|
] {
|
||||||
assert!(
|
assert!(
|
||||||
surface_route.contains(pattern),
|
surface_route.contains(pattern),
|
||||||
"aether-ai-surfaces planner/route.rs should own HTTP stream matching surface logic {pattern}"
|
"aether-ai-formats planner/route.rs should own HTTP stream matching format surface logic {pattern}"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3329,8 +3321,8 @@ fn ai_serving_m5_moves_contracts_and_route_logic_into_surface_crate() {
|
|||||||
"pub(crate) fn resolve_execution_runtime_stream_plan_kind(",
|
"pub(crate) fn resolve_execution_runtime_stream_plan_kind(",
|
||||||
"pub(crate) fn resolve_execution_runtime_sync_plan_kind(",
|
"pub(crate) fn resolve_execution_runtime_sync_plan_kind(",
|
||||||
"pub(crate) fn is_matching_stream_request(",
|
"pub(crate) fn is_matching_stream_request(",
|
||||||
"pub(crate) fn supports_sync_scheduler_decision_kind(",
|
"pub(crate) fn supports_sync_execution_decision_kind(",
|
||||||
"pub(crate) fn supports_stream_scheduler_decision_kind(",
|
"pub(crate) fn supports_stream_execution_decision_kind(",
|
||||||
] {
|
] {
|
||||||
assert!(
|
assert!(
|
||||||
gateway_api.contains(pattern),
|
gateway_api.contains(pattern),
|
||||||
@@ -3363,14 +3355,14 @@ fn ai_serving_m5_moves_contracts_and_route_logic_into_surface_crate() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ai_serving_m5_moves_kiro_stream_helpers_into_surface_crate() {
|
fn ai_serving_m5_moves_kiro_stream_helpers_into_format_crate() {
|
||||||
assert!(
|
assert!(
|
||||||
workspace_file_exists("crates/aether-ai-surfaces/src/adaptation/kiro_stream.rs"),
|
workspace_file_exists("crates/aether-ai-formats/src/provider_compat/kiro_stream.rs"),
|
||||||
"crates/aether-ai-surfaces/src/adaptation/kiro_stream.rs should exist after kiro helper extraction"
|
"crates/aether-ai-formats/src/provider_compat/kiro_stream.rs should exist after kiro helper extraction"
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
workspace_file_exists("crates/aether-ai-surfaces/src/adaptation/kiro_stream/state.rs"),
|
workspace_file_exists("crates/aether-ai-formats/src/provider_compat/kiro_stream/state.rs"),
|
||||||
"crates/aether-ai-surfaces/src/adaptation/kiro_stream/state.rs should own the Kiro stream state machine"
|
"crates/aether-ai-formats/src/provider_compat/kiro_stream/state.rs should own the Kiro stream state machine"
|
||||||
);
|
);
|
||||||
|
|
||||||
for path in [
|
for path in [
|
||||||
@@ -3384,10 +3376,10 @@ fn ai_serving_m5_moves_kiro_stream_helpers_into_surface_crate() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let surface_api = read_workspace_file("crates/aether-ai-surfaces/src/api.rs");
|
let surface_api = read_workspace_file("crates/aether-ai-formats/src/api.rs");
|
||||||
assert!(
|
assert!(
|
||||||
surface_api.contains("KiroToClaudeCliStreamState"),
|
surface_api.contains("KiroToClaudeCliStreamState"),
|
||||||
"aether-ai-surfaces api should export KiroToClaudeCliStreamState"
|
"aether-ai-formats api should export KiroToClaudeCliStreamState"
|
||||||
);
|
);
|
||||||
|
|
||||||
for file in collect_workspace_rust_files("apps/aether-gateway/src/ai_serving") {
|
for file in collect_workspace_rust_files("apps/aether-gateway/src/ai_serving") {
|
||||||
@@ -3419,9 +3411,9 @@ fn ai_serving_m5_moves_kiro_stream_helpers_into_surface_crate() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ai_serving_private_envelope_stream_normalizer_is_owned_by_surface_crate() {
|
fn ai_serving_private_envelope_stream_normalizer_is_owned_by_format_crate() {
|
||||||
assert!(
|
assert!(
|
||||||
workspace_file_exists("crates/aether-ai-surfaces/src/adaptation/private_envelope.rs"),
|
workspace_file_exists("crates/aether-ai-formats/src/provider_compat/private_envelope.rs"),
|
||||||
"surface private envelope adapter should exist"
|
"surface private envelope adapter should exist"
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
@@ -3438,7 +3430,7 @@ fn ai_serving_private_envelope_stream_normalizer_is_owned_by_surface_crate() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let surface_private_envelope =
|
let surface_private_envelope =
|
||||||
read_workspace_file("crates/aether-ai-surfaces/src/adaptation/private_envelope.rs");
|
read_workspace_file("crates/aether-ai-formats/src/provider_compat/private_envelope.rs");
|
||||||
for expected in [
|
for expected in [
|
||||||
"pub struct ProviderPrivateStreamNormalizer",
|
"pub struct ProviderPrivateStreamNormalizer",
|
||||||
"pub fn maybe_build_provider_private_stream_normalizer",
|
"pub fn maybe_build_provider_private_stream_normalizer",
|
||||||
@@ -3551,7 +3543,7 @@ fn ai_serving_planner_route_remains_control_only() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ai_serving_error_body_is_owned_by_surface_finalize_crate() {
|
fn ai_serving_error_body_is_owned_by_format_finalize_module() {
|
||||||
assert!(
|
assert!(
|
||||||
!workspace_file_exists("apps/aether-gateway/src/ai_serving/conversion"),
|
!workspace_file_exists("apps/aether-gateway/src/ai_serving/conversion"),
|
||||||
"gateway ai_serving should not keep a conversion directory; format conversion belongs to aether-ai-formats and transport checks belong to provider transport"
|
"gateway ai_serving should not keep a conversion directory; format conversion belongs to aether-ai-formats and transport checks belong to provider transport"
|
||||||
@@ -3561,12 +3553,12 @@ fn ai_serving_error_body_is_owned_by_surface_finalize_crate() {
|
|||||||
"ai_serving/conversion/error.rs should stay removed"
|
"ai_serving/conversion/error.rs should stay removed"
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
workspace_file_exists("crates/aether-ai-surfaces/src/finalize/error_body.rs"),
|
workspace_file_exists("crates/aether-ai-formats/src/response/error_body.rs"),
|
||||||
"surface error response-body helpers should live under finalize/error_body.rs"
|
"format error response-body helpers should live under finalize/error_body.rs"
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
!workspace_file_exists("crates/aether-ai-surfaces/src/conversion/error.rs"),
|
!workspace_file_exists("crates/aether-ai-formats/src/protocol/conversion/error.rs"),
|
||||||
"aether-ai-surfaces should not keep error response-body helpers under conversion"
|
"aether-ai-formats should not keep error response-body helpers under conversion"
|
||||||
);
|
);
|
||||||
|
|
||||||
let gateway_ai_serving_mod = read_workspace_file("apps/aether-gateway/src/ai_serving/mod.rs");
|
let gateway_ai_serving_mod = read_workspace_file("apps/aether-gateway/src/ai_serving/mod.rs");
|
||||||
@@ -3590,13 +3582,9 @@ fn ai_serving_error_body_is_owned_by_surface_finalize_crate() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn ai_serving_conversion_request_is_owned_by_format_crate() {
|
fn ai_serving_conversion_request_is_owned_by_format_crate() {
|
||||||
assert!(
|
assert!(
|
||||||
workspace_file_exists("crates/aether-ai-formats/src/conversion/request/mod.rs"),
|
workspace_file_exists("crates/aether-ai-formats/src/protocol/conversion/request/mod.rs"),
|
||||||
"request conversion should live in aether-ai-formats"
|
"request conversion should live in aether-ai-formats"
|
||||||
);
|
);
|
||||||
assert!(
|
|
||||||
!workspace_file_exists("crates/aether-ai-surfaces/src/conversion/request/mod.rs"),
|
|
||||||
"aether-ai-surfaces should not keep request conversion wrappers"
|
|
||||||
);
|
|
||||||
assert!(
|
assert!(
|
||||||
!workspace_file_exists(
|
!workspace_file_exists(
|
||||||
"apps/aether-gateway/src/ai_serving/conversion/request/from_openai_chat/claude.rs"
|
"apps/aether-gateway/src/ai_serving/conversion/request/from_openai_chat/claude.rs"
|
||||||
@@ -3619,23 +3607,19 @@ fn ai_serving_conversion_request_is_owned_by_format_crate() {
|
|||||||
"gateway ai_serving/mod.rs should not keep request re-export shell after root-seam consolidation"
|
"gateway ai_serving/mod.rs should not keep request re-export shell after root-seam consolidation"
|
||||||
);
|
);
|
||||||
|
|
||||||
let surface_api = read_workspace_file("crates/aether-ai-surfaces/src/api.rs");
|
let surface_api = read_workspace_file("crates/aether-ai-formats/src/api.rs");
|
||||||
assert!(
|
assert!(
|
||||||
surface_api.contains("pub use aether_ai_formats::conversion::request::{"),
|
surface_api.contains("pub use aether_ai_formats::protocol::conversion::request::{"),
|
||||||
"surface API facade should re-export request conversion directly from aether-ai-formats"
|
"format API facade should re-export request conversion directly from aether-ai-formats"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ai_serving_conversion_response_is_owned_by_format_crate() {
|
fn ai_serving_conversion_response_is_owned_by_format_crate() {
|
||||||
assert!(
|
assert!(
|
||||||
workspace_file_exists("crates/aether-ai-formats/src/conversion/response/mod.rs"),
|
workspace_file_exists("crates/aether-ai-formats/src/protocol/conversion/response/mod.rs"),
|
||||||
"response conversion should live in aether-ai-formats"
|
"response conversion should live in aether-ai-formats"
|
||||||
);
|
);
|
||||||
assert!(
|
|
||||||
!workspace_file_exists("crates/aether-ai-surfaces/src/conversion/response/mod.rs"),
|
|
||||||
"aether-ai-surfaces should not keep response conversion wrappers"
|
|
||||||
);
|
|
||||||
assert!(
|
assert!(
|
||||||
!workspace_file_exists(
|
!workspace_file_exists(
|
||||||
"apps/aether-gateway/src/ai_serving/conversion/response/from_openai_chat/claude_chat.rs"
|
"apps/aether-gateway/src/ai_serving/conversion/response/from_openai_chat/claude_chat.rs"
|
||||||
@@ -3658,48 +3642,42 @@ fn ai_serving_conversion_response_is_owned_by_format_crate() {
|
|||||||
"gateway ai_serving/mod.rs should not keep response re-export shell after root-seam consolidation"
|
"gateway ai_serving/mod.rs should not keep response re-export shell after root-seam consolidation"
|
||||||
);
|
);
|
||||||
|
|
||||||
let surface_api = read_workspace_file("crates/aether-ai-surfaces/src/api.rs");
|
let surface_api = read_workspace_file("crates/aether-ai-formats/src/api.rs");
|
||||||
assert!(
|
assert!(
|
||||||
surface_api.contains("pub use aether_ai_formats::conversion::response::{"),
|
surface_api.contains("pub use aether_ai_formats::protocol::conversion::response::{"),
|
||||||
"surface API facade should re-export response conversion directly from aether-ai-formats"
|
"format API facade should re-export response conversion directly from aether-ai-formats"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ai_surfaces_no_longer_owns_conversion_directory() {
|
fn ai_format_crate_owns_conversion_and_surface_facade() {
|
||||||
assert!(
|
assert!(
|
||||||
!workspace_file_exists("crates/aether-ai-surfaces/src/conversion"),
|
workspace_file_exists("crates/aether-ai-formats/src/protocol/conversion"),
|
||||||
"aether-ai-surfaces should not keep a conversion directory; format conversion belongs to aether-ai-formats"
|
"aether-ai-formats should own the conversion directory"
|
||||||
);
|
);
|
||||||
|
|
||||||
let surface_lib = read_workspace_file("crates/aether-ai-surfaces/src/lib.rs");
|
let surface_lib = read_workspace_file("crates/aether-ai-formats/src/lib.rs");
|
||||||
assert!(
|
assert!(
|
||||||
!surface_lib.contains("pub mod conversion;"),
|
surface_lib.contains("pub mod protocol;"),
|
||||||
"aether-ai-surfaces lib.rs should not expose a conversion module"
|
"aether-ai-formats lib.rs should expose the protocol module"
|
||||||
);
|
);
|
||||||
|
|
||||||
let surface_api = read_workspace_file("crates/aether-ai-surfaces/src/api.rs");
|
let surface_api = read_workspace_file("crates/aether-ai-formats/src/api.rs");
|
||||||
for pattern in [
|
for pattern in [
|
||||||
"pub use aether_ai_formats::{",
|
"pub use aether_ai_formats::{",
|
||||||
"pub use aether_ai_formats::conversion::request::{",
|
"pub use aether_ai_formats::protocol::conversion::request::{",
|
||||||
"pub use aether_ai_formats::conversion::response::{",
|
"pub use aether_ai_formats::protocol::conversion::response::{",
|
||||||
"pub use crate::finalize::error_body::{",
|
"pub use crate::response::error_body::{",
|
||||||
] {
|
] {
|
||||||
assert!(
|
assert!(
|
||||||
surface_api.contains(pattern),
|
surface_api.contains(pattern),
|
||||||
"surface API facade should expose pure dependencies through {pattern}"
|
"format API facade should expose pure dependencies through {pattern}"
|
||||||
);
|
|
||||||
}
|
|
||||||
for forbidden in ["pub use crate::conversion::", "crate::conversion::"] {
|
|
||||||
assert!(
|
|
||||||
!surface_api.contains(forbidden),
|
|
||||||
"surface API facade should not route through the removed conversion module {forbidden}"
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ai_serving_finalize_standard_sync_response_converters_are_owned_by_surface_crate() {
|
fn ai_serving_finalize_standard_sync_response_converters_are_owned_by_format_crate() {
|
||||||
for path in [
|
for path in [
|
||||||
"apps/aether-gateway/src/ai_serving/finalize/standard/openai/sync/chat.rs",
|
"apps/aether-gateway/src/ai_serving/finalize/standard/openai/sync/chat.rs",
|
||||||
"apps/aether-gateway/src/ai_serving/finalize/standard/openai/sync/cli.rs",
|
"apps/aether-gateway/src/ai_serving/finalize/standard/openai/sync/cli.rs",
|
||||||
@@ -3766,18 +3744,18 @@ fn ai_serving_finalize_standard_sync_response_converters_are_owned_by_surface_cr
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ai_serving_finalize_stream_engine_is_owned_by_surface_crate() {
|
fn ai_serving_finalize_stream_engine_is_owned_by_format_crate() {
|
||||||
for path in [
|
for path in [
|
||||||
"crates/aether-ai-surfaces/src/finalize/sse.rs",
|
"crates/aether-ai-formats/src/response/sse.rs",
|
||||||
"crates/aether-ai-surfaces/src/finalize/standard/stream_core/common.rs",
|
"crates/aether-ai-formats/src/response/standard/stream_core/common.rs",
|
||||||
"crates/aether-ai-surfaces/src/finalize/standard/stream_core/format_matrix.rs",
|
"crates/aether-ai-formats/src/response/standard/stream_core/format_matrix.rs",
|
||||||
"crates/aether-ai-surfaces/src/finalize/standard/openai/stream.rs",
|
"crates/aether-ai-formats/src/response/standard/openai/stream.rs",
|
||||||
"crates/aether-ai-surfaces/src/finalize/standard/claude/stream.rs",
|
"crates/aether-ai-formats/src/response/standard/claude/stream.rs",
|
||||||
"crates/aether-ai-surfaces/src/finalize/standard/gemini/stream.rs",
|
"crates/aether-ai-formats/src/response/standard/gemini/stream.rs",
|
||||||
] {
|
] {
|
||||||
assert!(
|
assert!(
|
||||||
workspace_file_exists(path),
|
workspace_file_exists(path),
|
||||||
"{path} should exist in aether-ai-surfaces finalize engine"
|
"{path} should exist in aether-ai-formats finalize engine"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3809,7 +3787,7 @@ fn ai_serving_finalize_stream_engine_is_owned_by_surface_crate() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let surface_format_matrix = read_workspace_file(
|
let surface_format_matrix = read_workspace_file(
|
||||||
"crates/aether-ai-surfaces/src/finalize/standard/stream_core/format_matrix.rs",
|
"crates/aether-ai-formats/src/response/standard/stream_core/format_matrix.rs",
|
||||||
);
|
);
|
||||||
for pattern in [
|
for pattern in [
|
||||||
"pub struct StreamingStandardFormatMatrix",
|
"pub struct StreamingStandardFormatMatrix",
|
||||||
@@ -3831,18 +3809,18 @@ fn ai_serving_finalize_stream_engine_is_owned_by_surface_crate() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ai_serving_finalize_standard_sync_products_are_owned_by_surface_crate() {
|
fn ai_serving_finalize_standard_sync_products_are_owned_by_format_crate() {
|
||||||
assert!(
|
assert!(
|
||||||
workspace_file_exists("crates/aether-ai-surfaces/src/finalize/sync_products.rs"),
|
workspace_file_exists("crates/aether-ai-formats/src/response/sync_products.rs"),
|
||||||
"finalize sync_products should live in aether-ai-surfaces"
|
"finalize sync_products should live in aether-ai-formats"
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
workspace_file_exists("crates/aether-ai-surfaces/src/finalize/sync_to_stream.rs"),
|
workspace_file_exists("crates/aether-ai-formats/src/response/sync_to_stream.rs"),
|
||||||
"finalize sync-to-stream bridge should live in aether-ai-surfaces"
|
"finalize sync-to-stream bridge should live in aether-ai-formats"
|
||||||
);
|
);
|
||||||
|
|
||||||
let surface_sync_products =
|
let surface_sync_products =
|
||||||
read_workspace_file("crates/aether-ai-surfaces/src/finalize/sync_products.rs");
|
read_workspace_file("crates/aether-ai-formats/src/response/sync_products.rs");
|
||||||
for expected in [
|
for expected in [
|
||||||
"pub fn maybe_build_standard_cross_format_sync_product_from_normalized_payload(",
|
"pub fn maybe_build_standard_cross_format_sync_product_from_normalized_payload(",
|
||||||
"pub fn maybe_build_standard_same_format_sync_body_from_normalized_payload(",
|
"pub fn maybe_build_standard_same_format_sync_body_from_normalized_payload(",
|
||||||
@@ -3935,11 +3913,11 @@ fn ai_serving_finalize_standard_sync_products_are_owned_by_surface_crate() {
|
|||||||
gateway_internal_sync.contains(
|
gateway_internal_sync.contains(
|
||||||
"maybe_build_standard_sync_finalize_product_from_normalized_payload"
|
"maybe_build_standard_sync_finalize_product_from_normalized_payload"
|
||||||
),
|
),
|
||||||
"gateway internal/sync_finalize.rs should delegate normalized standard sync finalize dispatch to aether-ai-surfaces"
|
"gateway internal/sync_finalize.rs should delegate normalized standard sync finalize dispatch to aether-ai-formats"
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
gateway_internal_sync.contains("maybe_build_openai_image_sync_finalize_product"),
|
gateway_internal_sync.contains("maybe_build_openai_image_sync_finalize_product"),
|
||||||
"gateway internal/sync_finalize.rs should delegate OpenAI image sync finalize parsing to aether-ai-surfaces"
|
"gateway internal/sync_finalize.rs should delegate OpenAI image sync finalize parsing to aether-ai-formats"
|
||||||
);
|
);
|
||||||
for forbidden in [
|
for forbidden in [
|
||||||
"CODEX_OPENAI_IMAGE_DEFAULT_OUTPUT_FORMAT",
|
"CODEX_OPENAI_IMAGE_DEFAULT_OUTPUT_FORMAT",
|
||||||
@@ -3969,7 +3947,7 @@ fn ai_serving_finalize_standard_sync_products_are_owned_by_surface_crate() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let surface_openai_image_stream =
|
let surface_openai_image_stream =
|
||||||
read_workspace_file("crates/aether-ai-surfaces/src/finalize/openai_image_stream.rs");
|
read_workspace_file("crates/aether-ai-formats/src/response/openai_image_stream.rs");
|
||||||
for expected in [
|
for expected in [
|
||||||
"pub fn maybe_build_openai_image_sync_finalize_product(",
|
"pub fn maybe_build_openai_image_sync_finalize_product(",
|
||||||
"pub struct OpenAiImageSyncFinalizeProduct",
|
"pub struct OpenAiImageSyncFinalizeProduct",
|
||||||
@@ -3984,7 +3962,7 @@ fn ai_serving_finalize_standard_sync_products_are_owned_by_surface_crate() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let surface_sync_to_stream =
|
let surface_sync_to_stream =
|
||||||
read_workspace_file("crates/aether-ai-surfaces/src/finalize/sync_to_stream.rs");
|
read_workspace_file("crates/aether-ai-formats/src/response/sync_to_stream.rs");
|
||||||
for expected in [
|
for expected in [
|
||||||
"pub fn maybe_bridge_standard_sync_json_to_stream(",
|
"pub fn maybe_bridge_standard_sync_json_to_stream(",
|
||||||
"pub struct SyncToStreamBridgeOutcome",
|
"pub struct SyncToStreamBridgeOutcome",
|
||||||
@@ -4019,14 +3997,14 @@ fn ai_serving_finalize_standard_sync_products_are_owned_by_surface_crate() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ai_serving_finalize_stream_rewrite_matrix_is_owned_by_surface_crate() {
|
fn ai_serving_finalize_stream_rewrite_matrix_is_owned_by_format_crate() {
|
||||||
assert!(
|
assert!(
|
||||||
workspace_file_exists("crates/aether-ai-surfaces/src/finalize/stream_rewrite.rs"),
|
workspace_file_exists("crates/aether-ai-formats/src/response/stream_rewrite.rs"),
|
||||||
"finalize stream rewrite matrix should live in aether-ai-surfaces"
|
"finalize stream rewrite matrix should live in aether-ai-formats"
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
workspace_file_exists("crates/aether-ai-surfaces/src/finalize/openai_image_stream.rs"),
|
workspace_file_exists("crates/aether-ai-formats/src/response/openai_image_stream.rs"),
|
||||||
"OpenAI image stream rewrite state should live in aether-ai-surfaces"
|
"OpenAI image stream rewrite state should live in aether-ai-formats"
|
||||||
);
|
);
|
||||||
|
|
||||||
let gateway_stream_rewrite = read_workspace_file(
|
let gateway_stream_rewrite = read_workspace_file(
|
||||||
@@ -4034,7 +4012,7 @@ fn ai_serving_finalize_stream_rewrite_matrix_is_owned_by_surface_crate() {
|
|||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
gateway_stream_rewrite.contains("maybe_build_ai_surface_stream_rewriter"),
|
gateway_stream_rewrite.contains("maybe_build_ai_surface_stream_rewriter"),
|
||||||
"gateway internal stream_rewrite should delegate stream rewrite state machine to aether-ai-surfaces"
|
"gateway internal stream_rewrite should delegate stream rewrite state machine to aether-ai-formats"
|
||||||
);
|
);
|
||||||
|
|
||||||
for forbidden in [
|
for forbidden in [
|
||||||
@@ -4072,10 +4050,10 @@ fn ai_serving_finalize_stream_rewrite_matrix_is_owned_by_surface_crate() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ai_serving_planner_common_parser_is_owned_by_surface_crate() {
|
fn ai_serving_planner_common_parser_is_owned_by_format_crate() {
|
||||||
assert!(
|
assert!(
|
||||||
workspace_file_exists("crates/aether-ai-surfaces/src/planner/common.rs"),
|
workspace_file_exists("crates/aether-ai-formats/src/request/common.rs"),
|
||||||
"planner/common pure parser should exist in aether-ai-surfaces"
|
"planner/common pure parser should exist in aether-ai-formats"
|
||||||
);
|
);
|
||||||
|
|
||||||
let gateway_common =
|
let gateway_common =
|
||||||
@@ -4215,10 +4193,10 @@ fn ai_serving_root_owns_shared_gemini_request_path_parser() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ai_serving_planner_standard_normalize_is_owned_by_surface_crate() {
|
fn ai_serving_planner_standard_normalize_is_owned_by_format_crate() {
|
||||||
assert!(
|
assert!(
|
||||||
workspace_file_exists("crates/aether-ai-surfaces/src/planner/standard/normalize.rs"),
|
workspace_file_exists("crates/aether-ai-formats/src/request/standard/normalize.rs"),
|
||||||
"planner/standard/normalize should live in aether-ai-surfaces"
|
"planner/standard/normalize should live in aether-ai-formats"
|
||||||
);
|
);
|
||||||
|
|
||||||
let gateway_normalize =
|
let gateway_normalize =
|
||||||
@@ -4232,7 +4210,7 @@ fn ai_serving_planner_standard_normalize_is_owned_by_surface_crate() {
|
|||||||
assert!(
|
assert!(
|
||||||
gateway_normalize_chat.contains("crate::ai_serving::")
|
gateway_normalize_chat.contains("crate::ai_serving::")
|
||||||
&& gateway_normalize_cli.contains("crate::ai_serving::"),
|
&& gateway_normalize_cli.contains("crate::ai_serving::"),
|
||||||
"gateway normalize chat/cli owners should delegate to surface standard normalize helpers through the ai_serving root seam"
|
"gateway normalize chat/cli owners should delegate to format standard normalize helpers through the ai_serving root seam"
|
||||||
);
|
);
|
||||||
|
|
||||||
for forbidden in [
|
for forbidden in [
|
||||||
@@ -4278,10 +4256,10 @@ fn ai_serving_planner_standard_normalize_is_owned_by_surface_crate() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ai_serving_openai_helpers_are_owned_by_surface_crate() {
|
fn ai_serving_openai_helpers_are_owned_by_format_crate() {
|
||||||
assert!(
|
assert!(
|
||||||
workspace_file_exists("crates/aether-ai-surfaces/src/planner/openai.rs"),
|
workspace_file_exists("crates/aether-ai-formats/src/request/openai.rs"),
|
||||||
"planner/openai helper owner should exist in aether-ai-surfaces"
|
"planner/openai helper owner should exist in aether-ai-formats"
|
||||||
);
|
);
|
||||||
|
|
||||||
let gateway_openai_mod =
|
let gateway_openai_mod =
|
||||||
@@ -4313,17 +4291,17 @@ fn ai_serving_openai_helpers_are_owned_by_surface_crate() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn ai_serving_standard_matrix_delegates_format_conversion_to_format_crate() {
|
fn ai_serving_standard_matrix_delegates_format_conversion_to_format_crate() {
|
||||||
assert!(
|
assert!(
|
||||||
workspace_file_exists("crates/aether-ai-surfaces/src/planner/matrix.rs"),
|
workspace_file_exists("crates/aether-ai-formats/src/request/matrix.rs"),
|
||||||
"planner/matrix facade should live in aether-ai-surfaces"
|
"planner/matrix facade should live in aether-ai-formats"
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
workspace_file_exists("crates/aether-ai-surfaces/src/planner/standard/matrix.rs"),
|
workspace_file_exists("crates/aether-ai-formats/src/request/standard/matrix.rs"),
|
||||||
"surface standard request-body planner should live in aether-ai-surfaces"
|
"format standard request-body planner should live in aether-ai-formats"
|
||||||
);
|
);
|
||||||
for path in [
|
for path in [
|
||||||
"crates/aether-ai-formats/src/canonical.rs",
|
"crates/aether-ai-formats/src/protocol/canonical.rs",
|
||||||
"crates/aether-ai-formats/src/matrix.rs",
|
"crates/aether-ai-formats/src/protocol/matrix.rs",
|
||||||
"crates/aether-ai-formats/src/registry.rs",
|
"crates/aether-ai-formats/src/protocol/registry.rs",
|
||||||
] {
|
] {
|
||||||
assert!(
|
assert!(
|
||||||
workspace_file_exists(path),
|
workspace_file_exists(path),
|
||||||
@@ -4331,11 +4309,13 @@ fn ai_serving_standard_matrix_delegates_format_conversion_to_format_crate() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
let surface_matrix =
|
let surface_matrix =
|
||||||
read_workspace_file("crates/aether-ai-surfaces/src/planner/standard/matrix.rs");
|
read_workspace_file("crates/aether-ai-formats/src/request/standard/matrix.rs");
|
||||||
assert!(
|
assert!(
|
||||||
surface_matrix.contains("aether_ai_formats::registry::{convert_request, FormatContext}")
|
surface_matrix.contains("use aether_ai_formats::protocol::registry::{")
|
||||||
&& surface_matrix.contains("aether_ai_formats::conversion::request::{"),
|
&& surface_matrix.contains("convert_request")
|
||||||
"surface standard matrix should delegate format conversion to aether-ai-formats"
|
&& surface_matrix.contains("FormatContext")
|
||||||
|
&& surface_matrix.contains("aether_ai_formats::protocol::conversion::request::{"),
|
||||||
|
"format standard matrix should delegate format conversion to aether-ai-formats"
|
||||||
);
|
);
|
||||||
for forbidden in [
|
for forbidden in [
|
||||||
"pub fn convert_request(",
|
"pub fn convert_request(",
|
||||||
@@ -4344,14 +4324,9 @@ fn ai_serving_standard_matrix_delegates_format_conversion_to_format_crate() {
|
|||||||
] {
|
] {
|
||||||
assert!(
|
assert!(
|
||||||
!surface_matrix.contains(forbidden),
|
!surface_matrix.contains(forbidden),
|
||||||
"surface standard matrix should not own format conversion primitive {forbidden}"
|
"format standard matrix should not own format conversion primitive {forbidden}"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
assert!(
|
|
||||||
!workspace_file_exists("crates/aether-ai-surfaces/src/conversion"),
|
|
||||||
"aether-ai-surfaces should not keep a conversion directory"
|
|
||||||
);
|
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
!workspace_file_exists("apps/aether-gateway/src/ai_serving/planner/standard/matrix.rs"),
|
!workspace_file_exists("apps/aether-gateway/src/ai_serving/planner/standard/matrix.rs"),
|
||||||
"planner/standard/matrix.rs should stay removed after wrapper cleanup"
|
"planner/standard/matrix.rs should stay removed after wrapper cleanup"
|
||||||
@@ -4384,26 +4359,26 @@ fn ai_serving_standard_matrix_delegates_format_conversion_to_format_crate() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ai_serving_standard_family_specs_are_owned_by_surface_crate() {
|
fn ai_serving_standard_family_specs_are_owned_by_format_crate() {
|
||||||
assert!(
|
assert!(
|
||||||
workspace_file_exists("crates/aether-ai-surfaces/src/planner/standard/family.rs"),
|
workspace_file_exists("crates/aether-ai-formats/src/request/standard/family.rs"),
|
||||||
"planner/standard/family pure spec owner should live in aether-ai-surfaces"
|
"planner/standard/family pure spec owner should live in aether-ai-formats"
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
workspace_file_exists("crates/aether-ai-surfaces/src/planner/standard/claude/chat.rs"),
|
workspace_file_exists("crates/aether-ai-formats/src/request/standard/claude/chat.rs"),
|
||||||
"planner/standard/claude/chat pure spec resolver should live in aether-ai-surfaces"
|
"planner/standard/claude/chat pure spec resolver should live in aether-ai-formats"
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
workspace_file_exists("crates/aether-ai-surfaces/src/planner/standard/claude/cli.rs"),
|
workspace_file_exists("crates/aether-ai-formats/src/request/standard/claude/cli.rs"),
|
||||||
"planner/standard/claude/cli pure spec resolver should live in aether-ai-surfaces"
|
"planner/standard/claude/cli pure spec resolver should live in aether-ai-formats"
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
workspace_file_exists("crates/aether-ai-surfaces/src/planner/standard/gemini/chat.rs"),
|
workspace_file_exists("crates/aether-ai-formats/src/request/standard/gemini/chat.rs"),
|
||||||
"planner/standard/gemini/chat pure spec resolver should live in aether-ai-surfaces"
|
"planner/standard/gemini/chat pure spec resolver should live in aether-ai-formats"
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
workspace_file_exists("crates/aether-ai-surfaces/src/planner/standard/gemini/cli.rs"),
|
workspace_file_exists("crates/aether-ai-formats/src/request/standard/gemini/cli.rs"),
|
||||||
"planner/standard/gemini/cli pure spec resolver should live in aether-ai-surfaces"
|
"planner/standard/gemini/cli pure spec resolver should live in aether-ai-formats"
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
@@ -4438,7 +4413,7 @@ fn ai_serving_standard_family_specs_are_owned_by_surface_crate() {
|
|||||||
] {
|
] {
|
||||||
assert!(
|
assert!(
|
||||||
!workspace_file_exists(path),
|
!workspace_file_exists(path),
|
||||||
"{path} should be removed after moving pure spec resolvers into the surface crate"
|
"{path} should be removed after moving pure spec resolvers into the format crate"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4467,10 +4442,10 @@ fn ai_serving_standard_family_specs_are_owned_by_surface_crate() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ai_serving_same_format_provider_specs_are_owned_by_surface_crate() {
|
fn ai_serving_same_format_provider_specs_are_owned_by_format_crate() {
|
||||||
assert!(
|
assert!(
|
||||||
workspace_file_exists("crates/aether-ai-surfaces/src/planner/passthrough/provider.rs"),
|
workspace_file_exists("crates/aether-ai-formats/src/request/passthrough/provider.rs"),
|
||||||
"planner/passthrough/provider pure spec owner should live in aether-ai-surfaces"
|
"planner/passthrough/provider pure spec owner should live in aether-ai-formats"
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
@@ -4518,10 +4493,10 @@ fn ai_serving_same_format_provider_specs_are_owned_by_surface_crate() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ai_serving_passthrough_provider_specs_are_owned_by_surface_crate() {
|
fn ai_serving_passthrough_provider_specs_are_owned_by_format_crate() {
|
||||||
assert!(
|
assert!(
|
||||||
workspace_file_exists("crates/aether-ai-surfaces/src/planner/passthrough/provider.rs"),
|
workspace_file_exists("crates/aether-ai-formats/src/request/passthrough/provider.rs"),
|
||||||
"planner/passthrough/provider pure spec owner should live in aether-ai-surfaces"
|
"planner/passthrough/provider pure spec owner should live in aether-ai-formats"
|
||||||
);
|
);
|
||||||
|
|
||||||
let family_types = read_workspace_file(
|
let family_types = read_workspace_file(
|
||||||
@@ -4563,10 +4538,10 @@ fn ai_serving_passthrough_provider_specs_are_owned_by_surface_crate() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ai_serving_specialized_files_specs_are_owned_by_surface_crate() {
|
fn ai_serving_specialized_files_specs_are_owned_by_format_crate() {
|
||||||
assert!(
|
assert!(
|
||||||
workspace_file_exists("crates/aether-ai-surfaces/src/planner/specialized/files.rs"),
|
workspace_file_exists("crates/aether-ai-formats/src/request/specialized/files.rs"),
|
||||||
"planner/specialized/files pure spec owner should live in aether-ai-surfaces"
|
"planner/specialized/files pure spec owner should live in aether-ai-formats"
|
||||||
);
|
);
|
||||||
|
|
||||||
let files =
|
let files =
|
||||||
@@ -4593,10 +4568,10 @@ fn ai_serving_specialized_files_specs_are_owned_by_surface_crate() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ai_serving_specialized_video_specs_are_owned_by_surface_crate() {
|
fn ai_serving_specialized_video_specs_are_owned_by_format_crate() {
|
||||||
assert!(
|
assert!(
|
||||||
workspace_file_exists("crates/aether-ai-surfaces/src/planner/specialized/video.rs"),
|
workspace_file_exists("crates/aether-ai-formats/src/request/specialized/video.rs"),
|
||||||
"planner/specialized/video pure spec owner should live in aether-ai-surfaces"
|
"planner/specialized/video pure spec owner should live in aether-ai-formats"
|
||||||
);
|
);
|
||||||
|
|
||||||
let video =
|
let video =
|
||||||
@@ -4621,10 +4596,10 @@ fn ai_serving_specialized_video_specs_are_owned_by_surface_crate() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ai_serving_openai_responses_specs_are_owned_by_surface_crate() {
|
fn ai_serving_openai_responses_specs_are_owned_by_format_crate() {
|
||||||
assert!(
|
assert!(
|
||||||
workspace_file_exists("crates/aether-ai-surfaces/src/planner/standard/openai_responses.rs"),
|
workspace_file_exists("crates/aether-ai-formats/src/request/standard/openai_responses.rs"),
|
||||||
"planner/standard/openai_responses pure spec owner should live in aether-ai-surfaces"
|
"planner/standard/openai_responses pure spec owner should live in aether-ai-formats"
|
||||||
);
|
);
|
||||||
|
|
||||||
let decision = read_workspace_file(
|
let decision = read_workspace_file(
|
||||||
@@ -4663,9 +4638,9 @@ fn ai_serving_openai_responses_specs_are_owned_by_surface_crate() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn ai_serving_legacy_api_format_names_stay_out_of_primary_paths() {
|
fn ai_serving_legacy_api_format_names_stay_out_of_primary_paths() {
|
||||||
for path in [
|
for path in [
|
||||||
"crates/aether-ai-surfaces/src/contracts/plan_kinds.rs",
|
"crates/aether-ai-formats/src/contracts/plan_kinds.rs",
|
||||||
"crates/aether-ai-surfaces/src/planner/route.rs",
|
"crates/aether-ai-formats/src/request/route.rs",
|
||||||
"crates/aether-ai-surfaces/src/planner/standard/openai_responses.rs",
|
"crates/aether-ai-formats/src/request/standard/openai_responses.rs",
|
||||||
"apps/aether-gateway/src/ai_serving/planner/decision/control_plan.rs",
|
"apps/aether-gateway/src/ai_serving/planner/decision/control_plan.rs",
|
||||||
"apps/aether-gateway/src/execution_runtime/fallback.rs",
|
"apps/aether-gateway/src/execution_runtime/fallback.rs",
|
||||||
] {
|
] {
|
||||||
@@ -4689,7 +4664,7 @@ fn ai_serving_legacy_api_format_names_stay_out_of_primary_paths() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let registry = read_workspace_file("crates/aether-ai-formats/src/registry.rs");
|
let registry = read_workspace_file("crates/aether-ai-formats/src/protocol/registry.rs");
|
||||||
let implementation = registry
|
let implementation = registry
|
||||||
.split("#[cfg(test)]")
|
.split("#[cfg(test)]")
|
||||||
.next()
|
.next()
|
||||||
@@ -4722,9 +4697,9 @@ fn retired_api_format_occurrences_are_whitelisted() {
|
|||||||
|
|
||||||
let allowed_paths = [
|
let allowed_paths = [
|
||||||
"apps/aether-gateway/src/handlers/admin/provider/write/normalize.rs",
|
"apps/aether-gateway/src/handlers/admin/provider/write/normalize.rs",
|
||||||
"crates/aether-ai-formats/src/formats.rs",
|
"crates/aether-ai-formats/src/protocol/formats.rs",
|
||||||
"crates/aether-ai-formats/src/matrix.rs",
|
"crates/aether-ai-formats/src/protocol/matrix.rs",
|
||||||
"crates/aether-ai-formats/src/registry.rs",
|
"crates/aether-ai-formats/src/protocol/registry.rs",
|
||||||
"crates/aether-data/src/migrate.rs",
|
"crates/aether-data/src/migrate.rs",
|
||||||
"crates/aether-usage-runtime/src/report.rs",
|
"crates/aether-usage-runtime/src/report.rs",
|
||||||
"frontend/src/api/endpoints/types/__tests__/api-format.spec.ts",
|
"frontend/src/api/endpoints/types/__tests__/api-format.spec.ts",
|
||||||
|
|||||||
@@ -4,10 +4,15 @@ version = "0.1.0"
|
|||||||
edition.workspace = true
|
edition.workspace = true
|
||||||
license.workspace = true
|
license.workspace = true
|
||||||
repository.workspace = true
|
repository.workspace = true
|
||||||
description = "Canonical AI format IR and adapters for Aether"
|
description = "Pure AI API format, surface, planning, and finalize logic for Aether"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
aether-contracts.workspace = true
|
||||||
|
base64.workspace = true
|
||||||
|
http.workspace = true
|
||||||
regex.workspace = true
|
regex.workspace = true
|
||||||
serde.workspace = true
|
serde.workspace = true
|
||||||
serde_json.workspace = true
|
serde_json.workspace = true
|
||||||
|
sha1 = "0.10"
|
||||||
|
sha2.workspace = true
|
||||||
uuid.workspace = true
|
uuid.workspace = true
|
||||||
|
|||||||
@@ -1,29 +1,8 @@
|
|||||||
pub use crate::adaptation::kiro_stream::{
|
|
||||||
build_kiro_final_message_sse_events, build_kiro_initial_sse_events,
|
|
||||||
build_kiro_stream_error_sse_events, calculate_kiro_context_input_tokens,
|
|
||||||
encode_kiro_sse_events, estimate_kiro_tokens, find_kiro_real_thinking_end_tag,
|
|
||||||
find_kiro_real_thinking_end_tag_at_buffer_end, find_kiro_real_thinking_start_tag, kiro_crc32,
|
|
||||||
KiroToClaudeCliStreamState, KIRO_MAX_THINKING_BUFFER,
|
|
||||||
};
|
|
||||||
pub use crate::adaptation::private_envelope::{
|
|
||||||
maybe_build_provider_private_stream_normalizer, normalize_provider_private_report_context,
|
|
||||||
normalize_provider_private_response_value, provider_private_response_allows_sync_finalize,
|
|
||||||
stream_body_contains_error_event, transform_provider_private_stream_line,
|
|
||||||
ProviderPrivateStreamNormalizer,
|
|
||||||
};
|
|
||||||
pub use crate::adaptation::surfaces::{
|
|
||||||
provider_adaptation_allows_sync_finalize_envelope, provider_adaptation_anchor_api_format,
|
|
||||||
provider_adaptation_descriptor_for_envelope, provider_adaptation_descriptor_for_provider_type,
|
|
||||||
provider_adaptation_requires_eventstream_accept,
|
|
||||||
provider_adaptation_should_unwrap_stream_envelope, ProviderAdaptationDescriptor,
|
|
||||||
ProviderAdaptationSurface, ANTIGRAVITY_V1INTERNAL_ENVELOPE_NAME,
|
|
||||||
GEMINI_CLI_V1INTERNAL_ENVELOPE_NAME, KIRO_ENVELOPE_NAME,
|
|
||||||
};
|
|
||||||
pub use crate::contracts::{
|
pub use crate::contracts::{
|
||||||
core_error_background_report_kind, core_error_default_client_api_format,
|
core_error_background_report_kind, core_error_default_client_api_format,
|
||||||
core_success_background_report_kind, implicit_sync_finalize_report_kind,
|
core_success_background_report_kind, implicit_sync_finalize_report_kind,
|
||||||
is_openai_responses_stream_plan_kind, is_openai_responses_sync_plan_kind,
|
is_openai_responses_stream_plan_kind, is_openai_responses_sync_plan_kind, AiControlPlanRequest,
|
||||||
ExecutionRuntimeAuthContext, GatewayControlPlanRequest, CLAUDE_CHAT_STREAM_PLAN_KIND,
|
ExecutionRuntimeAuthContext, CLAUDE_CHAT_STREAM_PLAN_KIND,
|
||||||
CLAUDE_CHAT_STREAM_SUCCESS_REPORT_KIND, CLAUDE_CHAT_SYNC_ERROR_REPORT_KIND,
|
CLAUDE_CHAT_STREAM_SUCCESS_REPORT_KIND, CLAUDE_CHAT_SYNC_ERROR_REPORT_KIND,
|
||||||
CLAUDE_CHAT_SYNC_FINALIZE_REPORT_KIND, CLAUDE_CHAT_SYNC_PLAN_KIND,
|
CLAUDE_CHAT_SYNC_FINALIZE_REPORT_KIND, CLAUDE_CHAT_SYNC_PLAN_KIND,
|
||||||
CLAUDE_CHAT_SYNC_SUCCESS_REPORT_KIND, CLAUDE_CLI_STREAM_PLAN_KIND,
|
CLAUDE_CHAT_SYNC_SUCCESS_REPORT_KIND, CLAUDE_CLI_STREAM_PLAN_KIND,
|
||||||
@@ -58,71 +37,47 @@ pub use crate::contracts::{
|
|||||||
OPENAI_VIDEO_CREATE_SYNC_PLAN_KIND, OPENAI_VIDEO_DELETE_SYNC_PLAN_KIND,
|
OPENAI_VIDEO_CREATE_SYNC_PLAN_KIND, OPENAI_VIDEO_DELETE_SYNC_PLAN_KIND,
|
||||||
OPENAI_VIDEO_REMIX_SYNC_PLAN_KIND,
|
OPENAI_VIDEO_REMIX_SYNC_PLAN_KIND,
|
||||||
};
|
};
|
||||||
pub use crate::finalize::common::{
|
pub use crate::provider_compat::kiro_stream::{
|
||||||
build_generated_tool_call_id, build_local_success_background_report,
|
build_kiro_final_message_sse_events, build_kiro_initial_sse_events,
|
||||||
build_local_success_conversion_background_report, canonicalize_tool_arguments,
|
build_kiro_stream_error_sse_events, calculate_kiro_context_input_tokens,
|
||||||
prepare_local_success_response_parts, prepare_local_success_response_parts_owned,
|
encode_kiro_sse_events, estimate_kiro_tokens, find_kiro_real_thinking_end_tag,
|
||||||
LocalSyncReportParts,
|
find_kiro_real_thinking_end_tag_at_buffer_end, find_kiro_real_thinking_start_tag, kiro_crc32,
|
||||||
|
KiroToClaudeCliStreamState, KIRO_MAX_THINKING_BUFFER,
|
||||||
};
|
};
|
||||||
pub use crate::finalize::error_body::{
|
pub use crate::provider_compat::private_envelope::{
|
||||||
build_core_error_body_for_client_format, is_core_error_finalize_kind, LocalCoreSyncErrorKind,
|
maybe_build_provider_private_stream_normalizer, normalize_provider_private_report_context,
|
||||||
|
normalize_provider_private_response_value, provider_private_response_allows_sync_finalize,
|
||||||
|
stream_body_contains_error_event, transform_provider_private_stream_line,
|
||||||
|
ProviderPrivateStreamNormalizer,
|
||||||
};
|
};
|
||||||
pub use crate::finalize::openai_image_stream::{
|
pub use crate::provider_compat::surfaces::{
|
||||||
maybe_build_openai_image_sync_finalize_product, OpenAiImageStreamState,
|
provider_adaptation_allows_sync_finalize_envelope, provider_adaptation_anchor_api_format,
|
||||||
OpenAiImageSyncFinalizeProduct,
|
provider_adaptation_descriptor_for_envelope, provider_adaptation_descriptor_for_provider_type,
|
||||||
|
provider_adaptation_requires_eventstream_accept,
|
||||||
|
provider_adaptation_should_unwrap_stream_envelope, ProviderAdaptationDescriptor,
|
||||||
|
ProviderAdaptationSurface, ANTIGRAVITY_V1INTERNAL_ENVELOPE_NAME,
|
||||||
|
GEMINI_CLI_V1INTERNAL_ENVELOPE_NAME, KIRO_ENVELOPE_NAME,
|
||||||
};
|
};
|
||||||
pub use crate::finalize::sse::{encode_done_sse, encode_json_sse, map_claude_stop_reason};
|
pub use crate::request::common::{
|
||||||
pub use crate::finalize::standard::claude::stream::{ClaudeClientEmitter, ClaudeProviderState};
|
|
||||||
pub use crate::finalize::standard::gemini::stream::{GeminiClientEmitter, GeminiProviderState};
|
|
||||||
pub use crate::finalize::standard::openai::stream::{
|
|
||||||
OpenAIChatClientEmitter, OpenAIChatProviderState, OpenAIResponsesClientEmitter,
|
|
||||||
OpenAIResponsesProviderState,
|
|
||||||
};
|
|
||||||
pub use crate::finalize::standard::stream_core::common::*;
|
|
||||||
pub use crate::finalize::standard::stream_core::{
|
|
||||||
CanonicalStreamFrame, StreamingStandardFormatMatrix, StreamingStandardTerminalObserver,
|
|
||||||
};
|
|
||||||
pub use crate::finalize::sync_products::{
|
|
||||||
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,
|
|
||||||
convert_standard_chat_response, convert_standard_cli_response,
|
|
||||||
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,
|
|
||||||
StandardCrossFormatSyncProduct, StandardSyncFinalizeNormalizedProduct,
|
|
||||||
};
|
|
||||||
pub use crate::finalize::sync_to_stream::{
|
|
||||||
maybe_bridge_standard_sync_json_to_stream, SyncToStreamBridgeOutcome,
|
|
||||||
};
|
|
||||||
pub use crate::finalize::{
|
|
||||||
maybe_build_ai_surface_stream_rewriter, resolve_finalize_stream_rewrite_mode,
|
|
||||||
AiSurfaceFinalizeError, AiSurfaceStreamRewriter, FinalizeStreamRewriteMode,
|
|
||||||
};
|
|
||||||
pub use crate::planner::common::{
|
|
||||||
force_upstream_streaming_for_provider, parse_direct_request_body,
|
force_upstream_streaming_for_provider, parse_direct_request_body,
|
||||||
};
|
};
|
||||||
pub use crate::planner::matrix::build_standard_request_body_from_canonical;
|
pub use crate::request::matrix::build_standard_request_body_from_canonical;
|
||||||
pub use crate::planner::openai::{
|
pub use crate::request::openai::{
|
||||||
copy_request_number_field, copy_request_number_field_as,
|
copy_request_number_field, copy_request_number_field_as,
|
||||||
map_openai_reasoning_effort_to_claude_output, map_openai_reasoning_effort_to_gemini_budget,
|
map_openai_reasoning_effort_to_claude_output, map_openai_reasoning_effort_to_gemini_budget,
|
||||||
parse_openai_stop_sequences, resolve_openai_chat_max_tokens, value_as_u64,
|
parse_openai_stop_sequences, resolve_openai_chat_max_tokens, value_as_u64,
|
||||||
};
|
};
|
||||||
pub use crate::planner::passthrough::provider::{
|
pub use crate::request::passthrough::provider::{
|
||||||
resolve_stream_spec as resolve_local_same_format_stream_spec,
|
resolve_stream_spec as resolve_local_same_format_stream_spec,
|
||||||
resolve_sync_spec as resolve_local_same_format_sync_spec, LocalSameFormatProviderFamily,
|
resolve_sync_spec as resolve_local_same_format_sync_spec, LocalSameFormatProviderFamily,
|
||||||
LocalSameFormatProviderSpec,
|
LocalSameFormatProviderSpec,
|
||||||
};
|
};
|
||||||
pub use crate::planner::route::{
|
pub use crate::request::route::{
|
||||||
is_matching_stream_http_request, is_matching_stream_request,
|
is_matching_stream_http_request, is_matching_stream_request,
|
||||||
resolve_execution_runtime_stream_plan_kind, resolve_execution_runtime_sync_plan_kind,
|
resolve_execution_runtime_stream_plan_kind, resolve_execution_runtime_sync_plan_kind,
|
||||||
supports_stream_scheduler_decision_kind, supports_sync_scheduler_decision_kind,
|
supports_stream_execution_decision_kind, supports_sync_execution_decision_kind,
|
||||||
};
|
};
|
||||||
pub use crate::planner::specialized::{
|
pub use crate::request::specialized::{
|
||||||
files::{
|
files::{
|
||||||
resolve_stream_spec as resolve_gemini_files_stream_spec,
|
resolve_stream_spec as resolve_gemini_files_stream_spec,
|
||||||
resolve_sync_spec as resolve_gemini_files_sync_spec, LocalGeminiFilesSpec,
|
resolve_sync_spec as resolve_gemini_files_sync_spec, LocalGeminiFilesSpec,
|
||||||
@@ -140,7 +95,7 @@ pub use crate::planner::specialized::{
|
|||||||
LocalVideoCreateSpec,
|
LocalVideoCreateSpec,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
pub use crate::planner::standard::{
|
pub use crate::request::standard::{
|
||||||
apply_codex_openai_responses_special_body_edits, apply_codex_openai_responses_special_headers,
|
apply_codex_openai_responses_special_body_edits, apply_codex_openai_responses_special_headers,
|
||||||
apply_openai_responses_compact_special_body_edits, build_cross_format_openai_chat_request_body,
|
apply_openai_responses_compact_special_body_edits, build_cross_format_openai_chat_request_body,
|
||||||
build_cross_format_openai_responses_request_body, build_local_openai_chat_request_body,
|
build_cross_format_openai_responses_request_body, build_local_openai_chat_request_body,
|
||||||
@@ -163,14 +118,59 @@ pub use crate::planner::standard::{
|
|||||||
CODEX_OPENAI_IMAGE_DEFAULT_VARIATION_MODEL, CODEX_OPENAI_IMAGE_DEFAULT_VARIATION_PROMPT,
|
CODEX_OPENAI_IMAGE_DEFAULT_VARIATION_MODEL, CODEX_OPENAI_IMAGE_DEFAULT_VARIATION_PROMPT,
|
||||||
CODEX_OPENAI_IMAGE_INTERNAL_MODEL,
|
CODEX_OPENAI_IMAGE_INTERNAL_MODEL,
|
||||||
};
|
};
|
||||||
pub use aether_ai_formats::conversion::request::{
|
pub use crate::response::common::{
|
||||||
|
build_generated_tool_call_id, build_local_success_background_report,
|
||||||
|
build_local_success_conversion_background_report, canonicalize_tool_arguments,
|
||||||
|
prepare_local_success_response_parts, prepare_local_success_response_parts_owned,
|
||||||
|
LocalSyncReportParts,
|
||||||
|
};
|
||||||
|
pub use crate::response::error_body::{
|
||||||
|
build_core_error_body_for_client_format, is_core_error_finalize_kind, LocalCoreSyncErrorKind,
|
||||||
|
};
|
||||||
|
pub use crate::response::openai_image_stream::{
|
||||||
|
maybe_build_openai_image_sync_finalize_product, OpenAiImageStreamState,
|
||||||
|
OpenAiImageSyncFinalizeProduct,
|
||||||
|
};
|
||||||
|
pub use crate::response::sse::{encode_done_sse, encode_json_sse, map_claude_stop_reason};
|
||||||
|
pub use crate::response::standard::claude::stream::{ClaudeClientEmitter, ClaudeProviderState};
|
||||||
|
pub use crate::response::standard::gemini::stream::{GeminiClientEmitter, GeminiProviderState};
|
||||||
|
pub use crate::response::standard::openai::stream::{
|
||||||
|
OpenAIChatClientEmitter, OpenAIChatProviderState, OpenAIResponsesClientEmitter,
|
||||||
|
OpenAIResponsesProviderState,
|
||||||
|
};
|
||||||
|
pub use crate::response::standard::stream_core::common::*;
|
||||||
|
pub use crate::response::standard::stream_core::{
|
||||||
|
CanonicalStreamFrame, StreamingStandardFormatMatrix, StreamingStandardTerminalObserver,
|
||||||
|
};
|
||||||
|
pub use crate::response::sync_products::{
|
||||||
|
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,
|
||||||
|
convert_standard_chat_response, convert_standard_cli_response,
|
||||||
|
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,
|
||||||
|
StandardCrossFormatSyncProduct, StandardSyncFinalizeNormalizedProduct,
|
||||||
|
};
|
||||||
|
pub use crate::response::sync_to_stream::{
|
||||||
|
maybe_bridge_standard_sync_json_to_stream, SyncToStreamBridgeOutcome,
|
||||||
|
};
|
||||||
|
pub use crate::response::{
|
||||||
|
maybe_build_ai_surface_stream_rewriter, resolve_finalize_stream_rewrite_mode,
|
||||||
|
AiSurfaceFinalizeError, AiSurfaceStreamRewriter, FinalizeStreamRewriteMode,
|
||||||
|
};
|
||||||
|
pub use aether_ai_formats::protocol::conversion::request::{
|
||||||
convert_openai_chat_request_to_claude_request, convert_openai_chat_request_to_gemini_request,
|
convert_openai_chat_request_to_claude_request, convert_openai_chat_request_to_gemini_request,
|
||||||
convert_openai_chat_request_to_openai_responses_request, extract_openai_text_content,
|
convert_openai_chat_request_to_openai_responses_request, extract_openai_text_content,
|
||||||
normalize_claude_request_to_openai_chat_request,
|
normalize_claude_request_to_openai_chat_request,
|
||||||
normalize_gemini_request_to_openai_chat_request,
|
normalize_gemini_request_to_openai_chat_request,
|
||||||
normalize_openai_responses_request_to_openai_chat_request, parse_openai_tool_result_content,
|
normalize_openai_responses_request_to_openai_chat_request, parse_openai_tool_result_content,
|
||||||
};
|
};
|
||||||
pub use aether_ai_formats::conversion::response::{
|
pub use aether_ai_formats::protocol::conversion::response::{
|
||||||
build_openai_responses_response, build_openai_responses_response_with_content,
|
build_openai_responses_response, build_openai_responses_response_with_content,
|
||||||
build_openai_responses_response_with_reasoning, convert_claude_chat_response_to_openai_chat,
|
build_openai_responses_response_with_reasoning, convert_claude_chat_response_to_openai_chat,
|
||||||
convert_claude_response_to_openai_responses, convert_gemini_chat_response_to_openai_chat,
|
convert_claude_response_to_openai_responses, convert_gemini_chat_response_to_openai_chat,
|
||||||
+7
-7
@@ -5,7 +5,7 @@ use serde::Serialize;
|
|||||||
use crate::contracts::ExecutionRuntimeAuthContext;
|
use crate::contracts::ExecutionRuntimeAuthContext;
|
||||||
|
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize)]
|
||||||
pub struct GatewayControlPlanRequest {
|
pub struct AiControlPlanRequest {
|
||||||
pub trace_id: String,
|
pub trace_id: String,
|
||||||
pub method: String,
|
pub method: String,
|
||||||
pub path: String,
|
pub path: String,
|
||||||
@@ -18,7 +18,7 @@ pub struct GatewayControlPlanRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn build_gateway_control_plan_request(
|
pub fn build_ai_control_plan_request(
|
||||||
trace_id: &str,
|
trace_id: &str,
|
||||||
method: &str,
|
method: &str,
|
||||||
path: &str,
|
path: &str,
|
||||||
@@ -27,8 +27,8 @@ pub fn build_gateway_control_plan_request(
|
|||||||
body_json: serde_json::Value,
|
body_json: serde_json::Value,
|
||||||
body_base64: Option<String>,
|
body_base64: Option<String>,
|
||||||
auth_context: Option<ExecutionRuntimeAuthContext>,
|
auth_context: Option<ExecutionRuntimeAuthContext>,
|
||||||
) -> GatewayControlPlanRequest {
|
) -> AiControlPlanRequest {
|
||||||
GatewayControlPlanRequest {
|
AiControlPlanRequest {
|
||||||
trace_id: trace_id.to_string(),
|
trace_id: trace_id.to_string(),
|
||||||
method: method.to_string(),
|
method: method.to_string(),
|
||||||
path: path.to_string(),
|
path: path.to_string(),
|
||||||
@@ -44,11 +44,11 @@ pub fn build_gateway_control_plan_request(
|
|||||||
mod tests {
|
mod tests {
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
use super::{build_gateway_control_plan_request, ExecutionRuntimeAuthContext};
|
use super::{build_ai_control_plan_request, ExecutionRuntimeAuthContext};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn build_gateway_control_plan_request_preserves_request_shape() {
|
fn build_ai_control_plan_request_preserves_request_shape() {
|
||||||
let payload = build_gateway_control_plan_request(
|
let payload = build_ai_control_plan_request(
|
||||||
"trace-123",
|
"trace-123",
|
||||||
"POST",
|
"POST",
|
||||||
"/v1/chat/completions",
|
"/v1/chat/completions",
|
||||||
+1
-1
@@ -9,7 +9,7 @@ pub use actions::{
|
|||||||
EXECUTION_RUNTIME_SYNC_ACTION, EXECUTION_RUNTIME_SYNC_DECISION_ACTION,
|
EXECUTION_RUNTIME_SYNC_ACTION, EXECUTION_RUNTIME_SYNC_DECISION_ACTION,
|
||||||
};
|
};
|
||||||
pub use auth_context::ExecutionRuntimeAuthContext;
|
pub use auth_context::ExecutionRuntimeAuthContext;
|
||||||
pub use control_payloads::{build_gateway_control_plan_request, GatewayControlPlanRequest};
|
pub use control_payloads::{build_ai_control_plan_request, AiControlPlanRequest};
|
||||||
pub use plan_kinds::{
|
pub use plan_kinds::{
|
||||||
is_openai_responses_stream_plan_kind, is_openai_responses_sync_plan_kind,
|
is_openai_responses_stream_plan_kind, is_openai_responses_sync_plan_kind,
|
||||||
CLAUDE_CHAT_STREAM_PLAN_KIND, CLAUDE_CHAT_SYNC_PLAN_KIND, CLAUDE_CLI_STREAM_PLAN_KIND,
|
CLAUDE_CHAT_STREAM_PLAN_KIND, CLAUDE_CHAT_SYNC_PLAN_KIND, CLAUDE_CLI_STREAM_PLAN_KIND,
|
||||||
@@ -1,14 +1,13 @@
|
|||||||
pub mod canonical;
|
extern crate self as aether_ai_formats;
|
||||||
pub mod context;
|
|
||||||
pub mod conversion;
|
|
||||||
pub mod formats;
|
|
||||||
pub mod matrix;
|
|
||||||
pub mod planner;
|
|
||||||
pub mod proxy;
|
|
||||||
pub mod registry;
|
|
||||||
pub mod stream;
|
|
||||||
|
|
||||||
pub use canonical::{
|
pub mod api;
|
||||||
|
pub mod contracts;
|
||||||
|
pub mod protocol;
|
||||||
|
pub mod provider_compat;
|
||||||
|
pub mod request;
|
||||||
|
pub mod response;
|
||||||
|
|
||||||
|
pub use protocol::canonical::{
|
||||||
canonical_request_unknown_block_count, canonical_response_unknown_block_count,
|
canonical_request_unknown_block_count, canonical_response_unknown_block_count,
|
||||||
canonical_to_claude_request, canonical_to_claude_response, canonical_to_gemini_request,
|
canonical_to_claude_request, canonical_to_claude_response, canonical_to_gemini_request,
|
||||||
canonical_to_gemini_response, canonical_to_openai_chat_request,
|
canonical_to_gemini_response, canonical_to_openai_chat_request,
|
||||||
@@ -24,16 +23,16 @@ pub use canonical::{
|
|||||||
CanonicalRole, CanonicalStopReason, CanonicalStreamEvent, CanonicalStreamFrame,
|
CanonicalRole, CanonicalStopReason, CanonicalStreamEvent, CanonicalStreamFrame,
|
||||||
CanonicalThinkingConfig, CanonicalToolChoice, CanonicalToolDefinition, CanonicalUsage,
|
CanonicalThinkingConfig, CanonicalToolChoice, CanonicalToolDefinition, CanonicalUsage,
|
||||||
};
|
};
|
||||||
pub use context::{FormatContext, FormatError};
|
pub use protocol::context::{FormatContext, FormatError};
|
||||||
pub use formats::{
|
pub use protocol::formats::{
|
||||||
api_format_alias_matches, api_format_storage_aliases, is_openai_responses_compact_format,
|
api_format_alias_matches, api_format_storage_aliases, is_openai_responses_compact_format,
|
||||||
is_openai_responses_family_format, is_openai_responses_format, normalize_api_format_alias,
|
is_openai_responses_family_format, is_openai_responses_format, normalize_api_format_alias,
|
||||||
FormatFamily, FormatId, FormatProfile,
|
FormatFamily, FormatId, FormatProfile,
|
||||||
};
|
};
|
||||||
pub use matrix::{
|
pub use protocol::matrix::{
|
||||||
request_candidate_api_format_preference, request_candidate_api_formats,
|
request_candidate_api_format_preference, request_candidate_api_formats,
|
||||||
request_conversion_kind, request_conversion_requires_enable_flag,
|
request_conversion_kind, request_conversion_requires_enable_flag,
|
||||||
sync_chat_response_conversion_kind, sync_cli_response_conversion_kind, RequestConversionKind,
|
sync_chat_response_conversion_kind, sync_cli_response_conversion_kind, RequestConversionKind,
|
||||||
SyncChatResponseConversionKind, SyncCliResponseConversionKind,
|
SyncChatResponseConversionKind, SyncCliResponseConversionKind,
|
||||||
};
|
};
|
||||||
pub use registry::{build_stream_transcoder, convert_request, convert_response};
|
pub use protocol::registry::{build_stream_transcoder, convert_request, convert_response};
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
pub mod openai;
|
|
||||||
+22
-18
@@ -3,9 +3,9 @@ use std::collections::BTreeMap;
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::{json, Map, Value};
|
use serde_json::{json, Map, Value};
|
||||||
|
|
||||||
use crate::planner::openai::map_thinking_budget_to_openai_reasoning_effort;
|
use crate::request::openai::map_thinking_budget_to_openai_reasoning_effort;
|
||||||
|
|
||||||
pub use crate::stream::{CanonicalStreamEvent, CanonicalStreamFrame};
|
pub use crate::protocol::stream::{CanonicalStreamEvent, CanonicalStreamFrame};
|
||||||
|
|
||||||
pub(crate) const OPENAI_RESPONSES_EXTENSION_NAMESPACE: &str = "openai_responses";
|
pub(crate) const OPENAI_RESPONSES_EXTENSION_NAMESPACE: &str = "openai_responses";
|
||||||
pub(crate) const OPENAI_RESPONSES_LEGACY_EXTENSION_NAMESPACE: &str = "openai_cli";
|
pub(crate) const OPENAI_RESPONSES_LEGACY_EXTENSION_NAMESPACE: &str = "openai_cli";
|
||||||
@@ -293,15 +293,15 @@ pub struct CanonicalResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_openai_chat_to_canonical_request(body_json: &Value) -> Option<CanonicalRequest> {
|
pub fn from_openai_chat_to_canonical_request(body_json: &Value) -> Option<CanonicalRequest> {
|
||||||
crate::formats::openai_chat::request::from_raw(body_json)
|
crate::protocol::formats::openai_chat::request::from_raw(body_json)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn canonical_to_openai_chat_request(canonical: &CanonicalRequest) -> Value {
|
pub fn canonical_to_openai_chat_request(canonical: &CanonicalRequest) -> Value {
|
||||||
crate::formats::openai_chat::request::to_raw(canonical)
|
crate::protocol::formats::openai_chat::request::to_raw(canonical)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_openai_responses_to_canonical_request(body_json: &Value) -> Option<CanonicalRequest> {
|
pub fn from_openai_responses_to_canonical_request(body_json: &Value) -> Option<CanonicalRequest> {
|
||||||
crate::formats::openai_responses::request::from_raw(body_json)
|
crate::protocol::formats::openai_responses::request::from_raw(body_json)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn canonical_to_openai_responses_request_with_profile(
|
pub(crate) fn canonical_to_openai_responses_request_with_profile(
|
||||||
@@ -310,7 +310,7 @@ pub(crate) fn canonical_to_openai_responses_request_with_profile(
|
|||||||
upstream_is_stream: bool,
|
upstream_is_stream: bool,
|
||||||
compact: bool,
|
compact: bool,
|
||||||
) -> Option<Value> {
|
) -> Option<Value> {
|
||||||
crate::formats::openai_responses::request::to_raw(
|
crate::protocol::formats::openai_responses::request::to_raw(
|
||||||
canonical,
|
canonical,
|
||||||
mapped_model,
|
mapped_model,
|
||||||
upstream_is_stream,
|
upstream_is_stream,
|
||||||
@@ -339,7 +339,7 @@ pub fn canonical_to_openai_responses_compact_request(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_claude_to_canonical_request(body_json: &Value) -> Option<CanonicalRequest> {
|
pub fn from_claude_to_canonical_request(body_json: &Value) -> Option<CanonicalRequest> {
|
||||||
crate::formats::claude_messages::request::from_raw(body_json)
|
crate::protocol::formats::claude_messages::request::from_raw(body_json)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn canonical_to_claude_request(
|
pub fn canonical_to_claude_request(
|
||||||
@@ -347,14 +347,18 @@ pub fn canonical_to_claude_request(
|
|||||||
mapped_model: &str,
|
mapped_model: &str,
|
||||||
upstream_is_stream: bool,
|
upstream_is_stream: bool,
|
||||||
) -> Option<Value> {
|
) -> Option<Value> {
|
||||||
crate::formats::claude_messages::request::to_raw(canonical, mapped_model, upstream_is_stream)
|
crate::protocol::formats::claude_messages::request::to_raw(
|
||||||
|
canonical,
|
||||||
|
mapped_model,
|
||||||
|
upstream_is_stream,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_gemini_to_canonical_request(
|
pub fn from_gemini_to_canonical_request(
|
||||||
body_json: &Value,
|
body_json: &Value,
|
||||||
request_path: &str,
|
request_path: &str,
|
||||||
) -> Option<CanonicalRequest> {
|
) -> Option<CanonicalRequest> {
|
||||||
crate::formats::gemini_generate_content::request::from_raw(body_json, request_path)
|
crate::protocol::formats::gemini_generate_content::request::from_raw(body_json, request_path)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn canonical_to_gemini_request(
|
pub fn canonical_to_gemini_request(
|
||||||
@@ -362,7 +366,7 @@ pub fn canonical_to_gemini_request(
|
|||||||
mapped_model: &str,
|
mapped_model: &str,
|
||||||
upstream_is_stream: bool,
|
upstream_is_stream: bool,
|
||||||
) -> Option<Value> {
|
) -> Option<Value> {
|
||||||
crate::formats::gemini_generate_content::request::to_raw(
|
crate::protocol::formats::gemini_generate_content::request::to_raw(
|
||||||
canonical,
|
canonical,
|
||||||
mapped_model,
|
mapped_model,
|
||||||
upstream_is_stream,
|
upstream_is_stream,
|
||||||
@@ -370,23 +374,23 @@ pub fn canonical_to_gemini_request(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_openai_chat_to_canonical_response(body_json: &Value) -> Option<CanonicalResponse> {
|
pub fn from_openai_chat_to_canonical_response(body_json: &Value) -> Option<CanonicalResponse> {
|
||||||
crate::formats::openai_chat::response::from_raw(body_json)
|
crate::protocol::formats::openai_chat::response::from_raw(body_json)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_openai_responses_to_canonical_response(body_json: &Value) -> Option<CanonicalResponse> {
|
pub fn from_openai_responses_to_canonical_response(body_json: &Value) -> Option<CanonicalResponse> {
|
||||||
crate::formats::openai_responses::response::from_raw(body_json)
|
crate::protocol::formats::openai_responses::response::from_raw(body_json)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_claude_to_canonical_response(body_json: &Value) -> Option<CanonicalResponse> {
|
pub fn from_claude_to_canonical_response(body_json: &Value) -> Option<CanonicalResponse> {
|
||||||
crate::formats::claude_messages::response::from_raw(body_json)
|
crate::protocol::formats::claude_messages::response::from_raw(body_json)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_gemini_to_canonical_response(body_json: &Value) -> Option<CanonicalResponse> {
|
pub fn from_gemini_to_canonical_response(body_json: &Value) -> Option<CanonicalResponse> {
|
||||||
crate::formats::gemini_generate_content::response::from_raw(body_json)
|
crate::protocol::formats::gemini_generate_content::response::from_raw(body_json)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn canonical_to_openai_chat_response(canonical: &CanonicalResponse) -> Value {
|
pub fn canonical_to_openai_chat_response(canonical: &CanonicalResponse) -> Value {
|
||||||
crate::formats::openai_chat::response::to_raw(canonical)
|
crate::protocol::formats::openai_chat::response::to_raw(canonical)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn canonical_blocks_to_openai_chat_message(content: &[CanonicalContentBlock]) -> Value {
|
pub(crate) fn canonical_blocks_to_openai_chat_message(content: &[CanonicalContentBlock]) -> Value {
|
||||||
@@ -524,7 +528,7 @@ pub(crate) fn canonical_to_openai_responses_response_with_profile(
|
|||||||
report_context: &Value,
|
report_context: &Value,
|
||||||
compact: bool,
|
compact: bool,
|
||||||
) -> Value {
|
) -> Value {
|
||||||
crate::formats::openai_responses::response::to_raw(canonical, report_context, compact)
|
crate::protocol::formats::openai_responses::response::to_raw(canonical, report_context, compact)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn canonical_to_openai_responses_response(
|
pub fn canonical_to_openai_responses_response(
|
||||||
@@ -542,14 +546,14 @@ pub fn canonical_to_openai_responses_compact_response(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn canonical_to_claude_response(canonical: &CanonicalResponse) -> Value {
|
pub fn canonical_to_claude_response(canonical: &CanonicalResponse) -> Value {
|
||||||
crate::formats::claude_messages::response::to_raw(canonical)
|
crate::protocol::formats::claude_messages::response::to_raw(canonical)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn canonical_to_gemini_response(
|
pub fn canonical_to_gemini_response(
|
||||||
canonical: &CanonicalResponse,
|
canonical: &CanonicalResponse,
|
||||||
report_context: &Value,
|
report_context: &Value,
|
||||||
) -> Option<Value> {
|
) -> Option<Value> {
|
||||||
crate::formats::gemini_generate_content::response::to_raw(canonical, report_context)
|
crate::protocol::formats::gemini_generate_content::response::to_raw(canonical, report_context)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn canonical_unknown_block_count(blocks: &[CanonicalContentBlock]) -> usize {
|
pub fn canonical_unknown_block_count(blocks: &[CanonicalContentBlock]) -> usize {
|
||||||
+1
-1
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
|
||||||
use crate::{context::FormatContext, registry};
|
use crate::protocol::{context::FormatContext, registry};
|
||||||
|
|
||||||
pub fn convert_openai_chat_request_to_claude_request(
|
pub fn convert_openai_chat_request_to_claude_request(
|
||||||
body_json: &Value,
|
body_json: &Value,
|
||||||
+1
-1
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
use serde_json::{json, Value};
|
use serde_json::{json, Value};
|
||||||
|
|
||||||
use crate::{context::FormatContext, registry};
|
use crate::protocol::{context::FormatContext, registry};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub struct OpenAiResponsesResponseUsage {
|
pub struct OpenAiResponsesResponseUsage {
|
||||||
+3
-3
@@ -1,7 +1,7 @@
|
|||||||
use serde_json::{json, Map, Value};
|
use serde_json::{json, Map, Value};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
canonical::{
|
protocol::canonical::{
|
||||||
canonical_extension_object_mut, canonical_instructions_to_claude_system,
|
canonical_extension_object_mut, canonical_instructions_to_claude_system,
|
||||||
canonical_messages_to_claude, canonical_openai_reasoning_effort,
|
canonical_messages_to_claude, canonical_openai_reasoning_effort,
|
||||||
canonical_tool_choice_to_claude, canonical_tools_to_claude, claude_extensions,
|
canonical_tool_choice_to_claude, canonical_tools_to_claude, claude_extensions,
|
||||||
@@ -11,8 +11,8 @@ use crate::{
|
|||||||
compact_canonical_claude_messages, insert_f64, namespace_extension_object,
|
compact_canonical_claude_messages, insert_f64, namespace_extension_object,
|
||||||
CanonicalRequest,
|
CanonicalRequest,
|
||||||
},
|
},
|
||||||
context::FormatContext,
|
protocol::context::FormatContext,
|
||||||
planner::openai::{
|
request::openai::{
|
||||||
map_openai_reasoning_effort_to_claude_output,
|
map_openai_reasoning_effort_to_claude_output,
|
||||||
map_openai_reasoning_effort_to_thinking_budget,
|
map_openai_reasoning_effort_to_thinking_budget,
|
||||||
},
|
},
|
||||||
+2
-2
@@ -3,13 +3,13 @@ use std::collections::BTreeMap;
|
|||||||
use serde_json::{json, Value};
|
use serde_json::{json, Value};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
canonical::{
|
protocol::canonical::{
|
||||||
canonical_blocks_to_claude, canonical_stop_reason_to_claude, canonical_usage_to_claude,
|
canonical_blocks_to_claude, canonical_stop_reason_to_claude, canonical_usage_to_claude,
|
||||||
claude_content_to_canonical_blocks, claude_extensions, claude_stop_reason_to_canonical,
|
claude_content_to_canonical_blocks, claude_extensions, claude_stop_reason_to_canonical,
|
||||||
claude_usage_to_canonical, namespace_extension_object, CanonicalResponse,
|
claude_usage_to_canonical, namespace_extension_object, CanonicalResponse,
|
||||||
CanonicalResponseOutput, CanonicalRole,
|
CanonicalResponseOutput, CanonicalRole,
|
||||||
},
|
},
|
||||||
context::FormatContext,
|
protocol::context::FormatContext,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn from(body: &Value, _ctx: &FormatContext) -> Option<CanonicalResponse> {
|
pub fn from(body: &Value, _ctx: &FormatContext) -> Option<CanonicalResponse> {
|
||||||
+3
-3
@@ -3,7 +3,7 @@ use std::collections::BTreeMap;
|
|||||||
use serde_json::{json, Map, Value};
|
use serde_json::{json, Map, Value};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
canonical::{
|
protocol::canonical::{
|
||||||
apply_gemini_request_extensions, canonical_extension_object_mut,
|
apply_gemini_request_extensions, canonical_extension_object_mut,
|
||||||
canonical_openai_reasoning_effort, extract_gemini_model_from_path,
|
canonical_openai_reasoning_effort, extract_gemini_model_from_path,
|
||||||
gemini_contents_to_canonical_messages, gemini_extensions, gemini_generation_config,
|
gemini_contents_to_canonical_messages, gemini_extensions, gemini_generation_config,
|
||||||
@@ -14,8 +14,8 @@ use crate::{
|
|||||||
CanonicalResponseFormat, CanonicalRole, CanonicalToolChoice, CanonicalToolDefinition,
|
CanonicalResponseFormat, CanonicalRole, CanonicalToolChoice, CanonicalToolDefinition,
|
||||||
OPENAI_RESPONSES_LEGACY_EXTENSION_NAMESPACE,
|
OPENAI_RESPONSES_LEGACY_EXTENSION_NAMESPACE,
|
||||||
},
|
},
|
||||||
context::FormatContext,
|
protocol::context::FormatContext,
|
||||||
planner::openai::map_openai_reasoning_effort_to_gemini_budget,
|
request::openai::map_openai_reasoning_effort_to_gemini_budget,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn from(body: &Value, ctx: &FormatContext) -> Option<CanonicalRequest> {
|
pub fn from(body: &Value, ctx: &FormatContext) -> Option<CanonicalRequest> {
|
||||||
+3
-3
@@ -1,13 +1,13 @@
|
|||||||
use serde_json::{json, Map, Value};
|
use serde_json::{json, Map, Value};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
canonical::{
|
protocol::canonical::{
|
||||||
canonical_extension_object_mut, gemini_extensions, gemini_part_to_canonical_block,
|
canonical_extension_object_mut, gemini_extensions, gemini_part_to_canonical_block,
|
||||||
gemini_stop_reason_to_canonical, gemini_usage_to_canonical, CanonicalContentBlock,
|
gemini_stop_reason_to_canonical, gemini_usage_to_canonical, CanonicalContentBlock,
|
||||||
CanonicalResponse, CanonicalResponseOutput, CanonicalRole, CanonicalStopReason,
|
CanonicalResponse, CanonicalResponseOutput, CanonicalRole, CanonicalStopReason,
|
||||||
CanonicalUsage,
|
CanonicalUsage,
|
||||||
},
|
},
|
||||||
context::FormatContext,
|
protocol::context::FormatContext,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn from(body: &Value, _ctx: &FormatContext) -> Option<CanonicalResponse> {
|
pub fn from(body: &Value, _ctx: &FormatContext) -> Option<CanonicalResponse> {
|
||||||
@@ -134,7 +134,7 @@ fn canonical_to_gemini_response(
|
|||||||
let outputs = if canonical.outputs.is_empty() {
|
let outputs = if canonical.outputs.is_empty() {
|
||||||
vec![CanonicalResponseOutput {
|
vec![CanonicalResponseOutput {
|
||||||
index: 0,
|
index: 0,
|
||||||
role: crate::canonical::CanonicalRole::Assistant,
|
role: crate::protocol::canonical::CanonicalRole::Assistant,
|
||||||
content: canonical.content.clone(),
|
content: canonical.content.clone(),
|
||||||
stop_reason: canonical.stop_reason.clone(),
|
stop_reason: canonical.stop_reason.clone(),
|
||||||
extensions: Default::default(),
|
extensions: Default::default(),
|
||||||
+12
-10
@@ -1,7 +1,7 @@
|
|||||||
use serde_json::{json, Value};
|
use serde_json::{json, Value};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
canonical::{
|
protocol::canonical::{
|
||||||
canonical_extension_object_mut, canonical_message_to_openai_chat,
|
canonical_extension_object_mut, canonical_message_to_openai_chat,
|
||||||
canonical_response_format_to_openai, canonical_tool_choice_to_openai,
|
canonical_response_format_to_openai, canonical_tool_choice_to_openai,
|
||||||
canonical_tool_to_openai, namespace_extension_object, openai_content_text,
|
canonical_tool_to_openai, namespace_extension_object, openai_content_text,
|
||||||
@@ -11,7 +11,7 @@ use crate::{
|
|||||||
CanonicalInstruction, CanonicalRequest, CanonicalRole, CanonicalThinkingConfig,
|
CanonicalInstruction, CanonicalRequest, CanonicalRole, CanonicalThinkingConfig,
|
||||||
OPENAI_RESPONSES_EXTENSION_NAMESPACE, OPENAI_RESPONSES_LEGACY_EXTENSION_NAMESPACE,
|
OPENAI_RESPONSES_EXTENSION_NAMESPACE, OPENAI_RESPONSES_LEGACY_EXTENSION_NAMESPACE,
|
||||||
},
|
},
|
||||||
context::FormatContext,
|
protocol::context::FormatContext,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn from(body: &Value, _ctx: &FormatContext) -> Option<CanonicalRequest> {
|
pub fn from(body: &Value, _ctx: &FormatContext) -> Option<CanonicalRequest> {
|
||||||
@@ -61,14 +61,16 @@ pub fn from_raw(body_json: &Value) -> Option<CanonicalRequest> {
|
|||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
canonical.messages.push(crate::canonical::CanonicalMessage {
|
canonical
|
||||||
role,
|
.messages
|
||||||
content: openai_message_content_blocks(message_object)?,
|
.push(crate::protocol::canonical::CanonicalMessage {
|
||||||
extensions: openai_extensions(
|
role,
|
||||||
message_object,
|
content: openai_message_content_blocks(message_object)?,
|
||||||
&["role", "content", "tool_calls", "tool_call_id"],
|
extensions: openai_extensions(
|
||||||
),
|
message_object,
|
||||||
});
|
&["role", "content", "tool_calls", "tool_call_id"],
|
||||||
|
),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
+2
-2
@@ -3,14 +3,14 @@ use std::collections::BTreeMap;
|
|||||||
use serde_json::{json, Value};
|
use serde_json::{json, Value};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
canonical::{
|
protocol::canonical::{
|
||||||
canonical_blocks_to_openai_chat_message, canonical_stop_reason_to_openai,
|
canonical_blocks_to_openai_chat_message, canonical_stop_reason_to_openai,
|
||||||
canonical_usage_to_openai, openai_extensions, openai_finish_reason_to_canonical,
|
canonical_usage_to_openai, openai_extensions, openai_finish_reason_to_canonical,
|
||||||
openai_message_content_blocks, openai_usage_to_canonical, CanonicalContentBlock,
|
openai_message_content_blocks, openai_usage_to_canonical, CanonicalContentBlock,
|
||||||
CanonicalResponse, CanonicalResponseOutput, CanonicalRole,
|
CanonicalResponse, CanonicalResponseOutput, CanonicalRole,
|
||||||
OPENAI_RESPONSES_EXTENSION_NAMESPACE, OPENAI_RESPONSES_LEGACY_EXTENSION_NAMESPACE,
|
OPENAI_RESPONSES_EXTENSION_NAMESPACE, OPENAI_RESPONSES_LEGACY_EXTENSION_NAMESPACE,
|
||||||
},
|
},
|
||||||
context::FormatContext,
|
protocol::context::FormatContext,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn from(body: &Value, _ctx: &FormatContext) -> Option<CanonicalResponse> {
|
pub fn from(body: &Value, _ctx: &FormatContext) -> Option<CanonicalResponse> {
|
||||||
+3
-3
@@ -1,7 +1,7 @@
|
|||||||
use serde_json::{json, Map, Value};
|
use serde_json::{json, Map, Value};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
canonical::{
|
protocol::canonical::{
|
||||||
canonical_response_format_to_openai, canonicalize_tool_arguments, media_data_or_url,
|
canonical_response_format_to_openai, canonicalize_tool_arguments, media_data_or_url,
|
||||||
namespace_extension_object, openai_content_text, openai_extensions,
|
namespace_extension_object, openai_content_text, openai_extensions,
|
||||||
openai_response_format_to_canonical, openai_responses_extension,
|
openai_response_format_to_canonical, openai_responses_extension,
|
||||||
@@ -11,8 +11,8 @@ use crate::{
|
|||||||
CanonicalThinkingConfig, CanonicalToolChoice, CanonicalToolDefinition,
|
CanonicalThinkingConfig, CanonicalToolChoice, CanonicalToolDefinition,
|
||||||
OPENAI_RESPONSES_EXTENSION_NAMESPACE, OPENAI_RESPONSES_LEGACY_EXTENSION_NAMESPACE,
|
OPENAI_RESPONSES_EXTENSION_NAMESPACE, OPENAI_RESPONSES_LEGACY_EXTENSION_NAMESPACE,
|
||||||
},
|
},
|
||||||
context::FormatContext,
|
protocol::context::FormatContext,
|
||||||
planner::openai::map_thinking_budget_to_openai_reasoning_effort,
|
request::openai::map_thinking_budget_to_openai_reasoning_effort,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn from(body: &Value, _ctx: &FormatContext) -> Option<CanonicalRequest> {
|
pub fn from(body: &Value, _ctx: &FormatContext) -> Option<CanonicalRequest> {
|
||||||
+2
-2
@@ -3,7 +3,7 @@ use std::collections::BTreeMap;
|
|||||||
use serde_json::{json, Map, Value};
|
use serde_json::{json, Map, Value};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
canonical::{
|
protocol::canonical::{
|
||||||
canonical_content_block_to_openai_responses_part,
|
canonical_content_block_to_openai_responses_part,
|
||||||
canonical_usage_to_openai_responses_usage, canonicalize_tool_arguments,
|
canonical_usage_to_openai_responses_usage, canonicalize_tool_arguments,
|
||||||
flush_openai_responses_message_item, namespace_extension_object,
|
flush_openai_responses_message_item, namespace_extension_object,
|
||||||
@@ -12,7 +12,7 @@ use crate::{
|
|||||||
CanonicalResponseOutput, CanonicalRole, CanonicalStopReason,
|
CanonicalResponseOutput, CanonicalRole, CanonicalStopReason,
|
||||||
OPENAI_RESPONSES_EXTENSION_NAMESPACE, OPENAI_RESPONSES_LEGACY_EXTENSION_NAMESPACE,
|
OPENAI_RESPONSES_EXTENSION_NAMESPACE, OPENAI_RESPONSES_LEGACY_EXTENSION_NAMESPACE,
|
||||||
},
|
},
|
||||||
context::FormatContext,
|
protocol::context::FormatContext,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn from(body: &Value, _ctx: &FormatContext) -> Option<CanonicalResponse> {
|
pub fn from(body: &Value, _ctx: &FormatContext) -> Option<CanonicalResponse> {
|
||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
api_format_alias_matches,
|
api_format_alias_matches,
|
||||||
formats::{is_openai_responses_compact_format, normalize_api_format_alias},
|
protocol::formats::{is_openai_responses_compact_format, normalize_api_format_alias},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
pub mod canonical;
|
||||||
|
pub mod context;
|
||||||
|
pub mod conversion;
|
||||||
|
pub mod formats;
|
||||||
|
pub mod matrix;
|
||||||
|
pub mod registry;
|
||||||
|
pub mod stream;
|
||||||
+7
-5
@@ -1,11 +1,13 @@
|
|||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
canonical::{CanonicalRequest, CanonicalResponse},
|
protocol::canonical::{CanonicalRequest, CanonicalResponse},
|
||||||
formats::{claude_messages, gemini_generate_content, openai_chat, openai_responses, FormatId},
|
protocol::formats::{
|
||||||
|
claude_messages, gemini_generate_content, openai_chat, openai_responses, FormatId,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use crate::context::{FormatContext, FormatError};
|
pub use crate::protocol::context::{FormatContext, FormatError};
|
||||||
|
|
||||||
pub fn parse_request(
|
pub fn parse_request(
|
||||||
source_format: &str,
|
source_format: &str,
|
||||||
@@ -144,7 +146,7 @@ mod tests {
|
|||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
|
|
||||||
use super::{convert_request, FormatContext};
|
use super::{convert_request, FormatContext};
|
||||||
use crate::formats::FormatId;
|
use crate::protocol::formats::FormatId;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn openai_cli_alias_is_not_a_primary_format() {
|
fn openai_cli_alias_is_not_a_primary_format() {
|
||||||
@@ -184,7 +186,7 @@ mod tests {
|
|||||||
] {
|
] {
|
||||||
assert!(
|
assert!(
|
||||||
!implementation.contains(forbidden),
|
!implementation.contains(forbidden),
|
||||||
"registry should dispatch through formats::<format> adapters, found {forbidden}"
|
"registry should dispatch through protocol::formats::<format> adapters, found {forbidden}"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+1
-1
@@ -4,7 +4,7 @@ use super::{
|
|||||||
AwsEventFrame, AwsHeaderValue, AwsHeaders, EventStreamDecoder, FrameParseError,
|
AwsEventFrame, AwsHeaderValue, AwsHeaders, EventStreamDecoder, FrameParseError,
|
||||||
MAX_BUFFER_SIZE, MAX_ERRORS, MAX_MESSAGE_SIZE,
|
MAX_BUFFER_SIZE, MAX_ERRORS, MAX_MESSAGE_SIZE,
|
||||||
};
|
};
|
||||||
use crate::adaptation::kiro_stream::kiro_crc32 as crc32;
|
use crate::provider_compat::kiro_stream::kiro_crc32 as crc32;
|
||||||
|
|
||||||
impl EventStreamDecoder {
|
impl EventStreamDecoder {
|
||||||
pub(super) fn feed(&mut self, data: &[u8]) -> Result<(), String> {
|
pub(super) fn feed(&mut self, data: &[u8]) -> Result<(), String> {
|
||||||
+2
-2
@@ -1,12 +1,12 @@
|
|||||||
use serde_json::{json, Value};
|
use serde_json::{json, Value};
|
||||||
|
|
||||||
use crate::adaptation::kiro_stream::{
|
use crate::provider_compat::kiro_stream::{
|
||||||
calculate_kiro_context_input_tokens, encode_kiro_sse_events, estimate_kiro_tokens,
|
calculate_kiro_context_input_tokens, encode_kiro_sse_events, estimate_kiro_tokens,
|
||||||
find_kiro_real_thinking_end_tag, find_kiro_real_thinking_end_tag_at_buffer_end,
|
find_kiro_real_thinking_end_tag, find_kiro_real_thinking_end_tag_at_buffer_end,
|
||||||
find_kiro_real_thinking_start_tag, KIRO_MAX_THINKING_BUFFER,
|
find_kiro_real_thinking_start_tag, KIRO_MAX_THINKING_BUFFER,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::finalize::AiSurfaceFinalizeError;
|
use crate::response::AiSurfaceFinalizeError;
|
||||||
|
|
||||||
use super::super::AwsEventFrame;
|
use super::super::AwsEventFrame;
|
||||||
use super::super::KiroClaudeStreamState;
|
use super::super::KiroClaudeStreamState;
|
||||||
+2
-2
@@ -1,9 +1,9 @@
|
|||||||
use crate::adaptation::kiro_stream::{
|
use crate::provider_compat::kiro_stream::{
|
||||||
build_kiro_final_message_sse_events, encode_kiro_sse_events,
|
build_kiro_final_message_sse_events, encode_kiro_sse_events,
|
||||||
find_kiro_real_thinking_end_tag_at_buffer_end,
|
find_kiro_real_thinking_end_tag_at_buffer_end,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::finalize::AiSurfaceFinalizeError;
|
use crate::response::AiSurfaceFinalizeError;
|
||||||
|
|
||||||
use super::super::KiroClaudeStreamState;
|
use super::super::KiroClaudeStreamState;
|
||||||
|
|
||||||
+2
-2
@@ -1,10 +1,10 @@
|
|||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use crate::adaptation::kiro_stream::{
|
use crate::provider_compat::kiro_stream::{
|
||||||
build_kiro_initial_sse_events, build_kiro_stream_error_sse_events, encode_kiro_sse_events,
|
build_kiro_initial_sse_events, build_kiro_stream_error_sse_events, encode_kiro_sse_events,
|
||||||
};
|
};
|
||||||
use crate::finalize::AiSurfaceFinalizeError;
|
use crate::response::AiSurfaceFinalizeError;
|
||||||
|
|
||||||
use super::super::{EventStreamDecoder, KiroClaudeStreamState, KiroToClaudeCliStreamState};
|
use super::super::{EventStreamDecoder, KiroClaudeStreamState, KiroToClaudeCliStreamState};
|
||||||
|
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
use crate::adaptation::kiro_stream::kiro_crc32 as crc32;
|
use crate::provider_compat::kiro_stream::kiro_crc32 as crc32;
|
||||||
use serde_json::{json, Value};
|
use serde_json::{json, Value};
|
||||||
|
|
||||||
use super::KiroToClaudeCliStreamState;
|
use super::KiroToClaudeCliStreamState;
|
||||||
+1
@@ -1,3 +1,4 @@
|
|||||||
pub mod kiro_stream;
|
pub mod kiro_stream;
|
||||||
pub mod private_envelope;
|
pub mod private_envelope;
|
||||||
|
pub mod proxy;
|
||||||
pub mod surfaces;
|
pub mod surfaces;
|
||||||
+2
-2
@@ -2,8 +2,8 @@ use std::collections::BTreeMap;
|
|||||||
|
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
|
||||||
use crate::adaptation::kiro_stream::KiroToClaudeCliStreamState;
|
use crate::provider_compat::kiro_stream::KiroToClaudeCliStreamState;
|
||||||
use crate::finalize::AiSurfaceFinalizeError;
|
use crate::response::AiSurfaceFinalizeError;
|
||||||
|
|
||||||
use super::surfaces::{
|
use super::surfaces::{
|
||||||
provider_adaptation_allows_sync_finalize_envelope, provider_adaptation_descriptor_for_envelope,
|
provider_adaptation_allows_sync_finalize_envelope, provider_adaptation_descriptor_for_envelope,
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
pub use crate::request::standard::matrix::build_standard_request_body_from_canonical;
|
||||||
+12
-12
@@ -14,7 +14,7 @@ use crate::contracts::{
|
|||||||
OPENAI_VIDEO_CREATE_SYNC_PLAN_KIND, OPENAI_VIDEO_DELETE_SYNC_PLAN_KIND,
|
OPENAI_VIDEO_CREATE_SYNC_PLAN_KIND, OPENAI_VIDEO_DELETE_SYNC_PLAN_KIND,
|
||||||
OPENAI_VIDEO_REMIX_SYNC_PLAN_KIND,
|
OPENAI_VIDEO_REMIX_SYNC_PLAN_KIND,
|
||||||
};
|
};
|
||||||
use crate::planner::specialized::image::is_openai_image_stream_request;
|
use crate::request::specialized::image::is_openai_image_stream_request;
|
||||||
|
|
||||||
pub fn resolve_execution_runtime_stream_plan_kind(
|
pub fn resolve_execution_runtime_stream_plan_kind(
|
||||||
route_class: Option<&str>,
|
route_class: Option<&str>,
|
||||||
@@ -313,7 +313,7 @@ pub fn is_matching_stream_http_request(
|
|||||||
is_matching_stream_request(plan_kind, parts.uri.path(), body_json)
|
is_matching_stream_request(plan_kind, parts.uri.path(), body_json)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn supports_sync_scheduler_decision_kind(plan_kind: &str) -> bool {
|
pub fn supports_sync_execution_decision_kind(plan_kind: &str) -> bool {
|
||||||
matches!(
|
matches!(
|
||||||
plan_kind,
|
plan_kind,
|
||||||
OPENAI_CHAT_SYNC_PLAN_KIND
|
OPENAI_CHAT_SYNC_PLAN_KIND
|
||||||
@@ -337,7 +337,7 @@ pub fn supports_sync_scheduler_decision_kind(plan_kind: &str) -> bool {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn supports_stream_scheduler_decision_kind(plan_kind: &str) -> bool {
|
pub fn supports_stream_execution_decision_kind(plan_kind: &str) -> bool {
|
||||||
matches!(
|
matches!(
|
||||||
plan_kind,
|
plan_kind,
|
||||||
OPENAI_CHAT_STREAM_PLAN_KIND
|
OPENAI_CHAT_STREAM_PLAN_KIND
|
||||||
@@ -361,7 +361,7 @@ mod tests {
|
|||||||
use super::{
|
use super::{
|
||||||
is_matching_stream_http_request, is_matching_stream_request,
|
is_matching_stream_http_request, is_matching_stream_request,
|
||||||
resolve_execution_runtime_stream_plan_kind, resolve_execution_runtime_sync_plan_kind,
|
resolve_execution_runtime_stream_plan_kind, resolve_execution_runtime_sync_plan_kind,
|
||||||
supports_stream_scheduler_decision_kind, supports_sync_scheduler_decision_kind,
|
supports_stream_execution_decision_kind, supports_sync_execution_decision_kind,
|
||||||
};
|
};
|
||||||
use crate::contracts::{
|
use crate::contracts::{
|
||||||
OPENAI_CHAT_STREAM_PLAN_KIND, OPENAI_CHAT_SYNC_PLAN_KIND, OPENAI_IMAGE_STREAM_PLAN_KIND,
|
OPENAI_CHAT_STREAM_PLAN_KIND, OPENAI_CHAT_SYNC_PLAN_KIND, OPENAI_IMAGE_STREAM_PLAN_KIND,
|
||||||
@@ -426,10 +426,10 @@ mod tests {
|
|||||||
),
|
),
|
||||||
Some(OPENAI_RESPONSES_SYNC_PLAN_KIND)
|
Some(OPENAI_RESPONSES_SYNC_PLAN_KIND)
|
||||||
);
|
);
|
||||||
assert!(supports_sync_scheduler_decision_kind(
|
assert!(supports_sync_execution_decision_kind(
|
||||||
OPENAI_RESPONSES_SYNC_PLAN_KIND
|
OPENAI_RESPONSES_SYNC_PLAN_KIND
|
||||||
));
|
));
|
||||||
assert!(supports_stream_scheduler_decision_kind(
|
assert!(supports_stream_execution_decision_kind(
|
||||||
OPENAI_RESPONSES_STREAM_PLAN_KIND
|
OPENAI_RESPONSES_STREAM_PLAN_KIND
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@@ -466,10 +466,10 @@ mod tests {
|
|||||||
),
|
),
|
||||||
Some(OPENAI_RESPONSES_COMPACT_SYNC_PLAN_KIND)
|
Some(OPENAI_RESPONSES_COMPACT_SYNC_PLAN_KIND)
|
||||||
);
|
);
|
||||||
assert!(supports_sync_scheduler_decision_kind(
|
assert!(supports_sync_execution_decision_kind(
|
||||||
OPENAI_RESPONSES_COMPACT_SYNC_PLAN_KIND
|
OPENAI_RESPONSES_COMPACT_SYNC_PLAN_KIND
|
||||||
));
|
));
|
||||||
assert!(supports_stream_scheduler_decision_kind(
|
assert!(supports_stream_execution_decision_kind(
|
||||||
OPENAI_RESPONSES_COMPACT_STREAM_PLAN_KIND
|
OPENAI_RESPONSES_COMPACT_STREAM_PLAN_KIND
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@@ -486,10 +486,10 @@ mod tests {
|
|||||||
"/v1/chat/completions",
|
"/v1/chat/completions",
|
||||||
&serde_json::json!({"stream": true}),
|
&serde_json::json!({"stream": true}),
|
||||||
));
|
));
|
||||||
assert!(supports_sync_scheduler_decision_kind(
|
assert!(supports_sync_execution_decision_kind(
|
||||||
OPENAI_CHAT_SYNC_PLAN_KIND
|
OPENAI_CHAT_SYNC_PLAN_KIND
|
||||||
));
|
));
|
||||||
assert!(supports_stream_scheduler_decision_kind(
|
assert!(supports_stream_execution_decision_kind(
|
||||||
OPENAI_CHAT_STREAM_PLAN_KIND
|
OPENAI_CHAT_STREAM_PLAN_KIND
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@@ -526,7 +526,7 @@ mod tests {
|
|||||||
),
|
),
|
||||||
Some(OPENAI_IMAGE_SYNC_PLAN_KIND)
|
Some(OPENAI_IMAGE_SYNC_PLAN_KIND)
|
||||||
);
|
);
|
||||||
assert!(supports_sync_scheduler_decision_kind(
|
assert!(supports_sync_execution_decision_kind(
|
||||||
OPENAI_IMAGE_SYNC_PLAN_KIND
|
OPENAI_IMAGE_SYNC_PLAN_KIND
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@@ -553,7 +553,7 @@ mod tests {
|
|||||||
),
|
),
|
||||||
Some(OPENAI_IMAGE_STREAM_PLAN_KIND)
|
Some(OPENAI_IMAGE_STREAM_PLAN_KIND)
|
||||||
);
|
);
|
||||||
assert!(supports_stream_scheduler_decision_kind(
|
assert!(supports_stream_execution_decision_kind(
|
||||||
OPENAI_IMAGE_STREAM_PLAN_KIND
|
OPENAI_IMAGE_STREAM_PLAN_KIND
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
+2
-2
@@ -4,7 +4,7 @@ use base64::Engine as _;
|
|||||||
use serde_json::{json, Map, Number, Value};
|
use serde_json::{json, Map, Number, Value};
|
||||||
|
|
||||||
use crate::contracts::{OPENAI_IMAGE_STREAM_PLAN_KIND, OPENAI_IMAGE_SYNC_PLAN_KIND};
|
use crate::contracts::{OPENAI_IMAGE_STREAM_PLAN_KIND, OPENAI_IMAGE_SYNC_PLAN_KIND};
|
||||||
use crate::planner::standard::{
|
use crate::request::standard::{
|
||||||
CODEX_OPENAI_IMAGE_DEFAULT_MODEL, CODEX_OPENAI_IMAGE_DEFAULT_VARIATION_MODEL,
|
CODEX_OPENAI_IMAGE_DEFAULT_MODEL, CODEX_OPENAI_IMAGE_DEFAULT_VARIATION_MODEL,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -808,7 +808,7 @@ mod tests {
|
|||||||
normalize_openai_image_request, resolve_stream_spec, resolve_sync_spec,
|
normalize_openai_image_request, resolve_stream_spec, resolve_sync_spec,
|
||||||
OpenAiImageOperation,
|
OpenAiImageOperation,
|
||||||
};
|
};
|
||||||
use crate::planner::standard::{
|
use crate::request::standard::{
|
||||||
apply_codex_openai_responses_special_body_edits, CODEX_OPENAI_IMAGE_INTERNAL_MODEL,
|
apply_codex_openai_responses_special_body_edits, CODEX_OPENAI_IMAGE_INTERNAL_MODEL,
|
||||||
};
|
};
|
||||||
|
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
use crate::contracts::{CLAUDE_CHAT_STREAM_PLAN_KIND, CLAUDE_CHAT_SYNC_PLAN_KIND};
|
use crate::contracts::{CLAUDE_CHAT_STREAM_PLAN_KIND, CLAUDE_CHAT_SYNC_PLAN_KIND};
|
||||||
use crate::planner::standard::family::{
|
use crate::request::standard::family::{
|
||||||
LocalStandardSourceFamily, LocalStandardSourceMode, LocalStandardSpec,
|
LocalStandardSourceFamily, LocalStandardSourceMode, LocalStandardSpec,
|
||||||
};
|
};
|
||||||
|
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
use crate::contracts::{CLAUDE_CLI_STREAM_PLAN_KIND, CLAUDE_CLI_SYNC_PLAN_KIND};
|
use crate::contracts::{CLAUDE_CLI_STREAM_PLAN_KIND, CLAUDE_CLI_SYNC_PLAN_KIND};
|
||||||
use crate::planner::standard::family::{
|
use crate::request::standard::family::{
|
||||||
LocalStandardSourceFamily, LocalStandardSourceMode, LocalStandardSpec,
|
LocalStandardSourceFamily, LocalStandardSourceMode, LocalStandardSpec,
|
||||||
};
|
};
|
||||||
|
|
||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
pub mod chat;
|
pub mod chat;
|
||||||
pub mod cli;
|
pub mod cli;
|
||||||
|
|
||||||
use crate::planner::standard::LocalStandardSpec;
|
use crate::request::standard::LocalStandardSpec;
|
||||||
|
|
||||||
pub fn resolve_sync_spec(plan_kind: &str) -> Option<LocalStandardSpec> {
|
pub fn resolve_sync_spec(plan_kind: &str) -> Option<LocalStandardSpec> {
|
||||||
chat::resolve_sync_spec(plan_kind).or_else(|| cli::resolve_sync_spec(plan_kind))
|
chat::resolve_sync_spec(plan_kind).or_else(|| cli::resolve_sync_spec(plan_kind))
|
||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
|
|
||||||
use aether_ai_formats::proxy::rules::body_rules_handle_path;
|
use aether_ai_formats::provider_compat::proxy::rules::body_rules_handle_path;
|
||||||
use serde_json::{json, Value};
|
use serde_json::{json, Value};
|
||||||
use sha1::{Digest as Sha1Digest, Sha1};
|
use sha1::{Digest as Sha1Digest, Sha1};
|
||||||
use sha2::Sha256;
|
use sha2::Sha256;
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
use crate::contracts::{GEMINI_CHAT_STREAM_PLAN_KIND, GEMINI_CHAT_SYNC_PLAN_KIND};
|
use crate::contracts::{GEMINI_CHAT_STREAM_PLAN_KIND, GEMINI_CHAT_SYNC_PLAN_KIND};
|
||||||
use crate::planner::standard::family::{
|
use crate::request::standard::family::{
|
||||||
LocalStandardSourceFamily, LocalStandardSourceMode, LocalStandardSpec,
|
LocalStandardSourceFamily, LocalStandardSourceMode, LocalStandardSpec,
|
||||||
};
|
};
|
||||||
|
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
use crate::contracts::{GEMINI_CLI_STREAM_PLAN_KIND, GEMINI_CLI_SYNC_PLAN_KIND};
|
use crate::contracts::{GEMINI_CLI_STREAM_PLAN_KIND, GEMINI_CLI_SYNC_PLAN_KIND};
|
||||||
use crate::planner::standard::family::{
|
use crate::request::standard::family::{
|
||||||
LocalStandardSourceFamily, LocalStandardSourceMode, LocalStandardSpec,
|
LocalStandardSourceFamily, LocalStandardSourceMode, LocalStandardSpec,
|
||||||
};
|
};
|
||||||
|
|
||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
pub mod chat;
|
pub mod chat;
|
||||||
pub mod cli;
|
pub mod cli;
|
||||||
|
|
||||||
use crate::planner::standard::LocalStandardSpec;
|
use crate::request::standard::LocalStandardSpec;
|
||||||
|
|
||||||
pub fn resolve_sync_spec(plan_kind: &str) -> Option<LocalStandardSpec> {
|
pub fn resolve_sync_spec(plan_kind: &str) -> Option<LocalStandardSpec> {
|
||||||
chat::resolve_sync_spec(plan_kind).or_else(|| cli::resolve_sync_spec(plan_kind))
|
chat::resolve_sync_spec(plan_kind).or_else(|| cli::resolve_sync_spec(plan_kind))
|
||||||
+3
-3
@@ -1,14 +1,14 @@
|
|||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use aether_ai_formats::conversion::request::{
|
use aether_ai_formats::protocol::conversion::request::{
|
||||||
convert_openai_chat_request_to_claude_request, convert_openai_chat_request_to_gemini_request,
|
convert_openai_chat_request_to_claude_request, convert_openai_chat_request_to_gemini_request,
|
||||||
convert_openai_chat_request_to_openai_responses_request,
|
convert_openai_chat_request_to_openai_responses_request,
|
||||||
normalize_claude_request_to_openai_chat_request,
|
normalize_claude_request_to_openai_chat_request,
|
||||||
normalize_gemini_request_to_openai_chat_request,
|
normalize_gemini_request_to_openai_chat_request,
|
||||||
normalize_openai_responses_request_to_openai_chat_request,
|
normalize_openai_responses_request_to_openai_chat_request,
|
||||||
};
|
};
|
||||||
use aether_ai_formats::proxy::rules::apply_local_body_rules;
|
use aether_ai_formats::protocol::registry::{convert_request, FormatContext};
|
||||||
use aether_ai_formats::registry::{convert_request, FormatContext};
|
use aether_ai_formats::provider_compat::proxy::rules::apply_local_body_rules;
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
use aether_ai_formats::conversion::request::{
|
use aether_ai_formats::protocol::conversion::request::{
|
||||||
convert_openai_chat_request_to_claude_request, convert_openai_chat_request_to_gemini_request,
|
convert_openai_chat_request_to_claude_request, convert_openai_chat_request_to_gemini_request,
|
||||||
convert_openai_chat_request_to_openai_responses_request,
|
convert_openai_chat_request_to_openai_responses_request,
|
||||||
normalize_openai_responses_request_to_openai_chat_request,
|
normalize_openai_responses_request_to_openai_chat_request,
|
||||||
+33
-1
@@ -28,6 +28,20 @@ pub fn canonicalize_tool_arguments(value: Option<Value>) -> String {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn remove_empty_pages_from_tool_arguments(arguments: &str) -> String {
|
||||||
|
let Ok(mut value) = serde_json::from_str::<Value>(arguments) else {
|
||||||
|
return arguments.to_string();
|
||||||
|
};
|
||||||
|
let Some(object) = value.as_object_mut() else {
|
||||||
|
return arguments.to_string();
|
||||||
|
};
|
||||||
|
if object.get("pages").and_then(Value::as_str) != Some("") {
|
||||||
|
return arguments.to_string();
|
||||||
|
}
|
||||||
|
object.remove("pages");
|
||||||
|
serde_json::to_string(&value).unwrap_or_else(|_| arguments.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn prepare_local_success_response_parts(
|
pub fn prepare_local_success_response_parts(
|
||||||
headers: &BTreeMap<String, String>,
|
headers: &BTreeMap<String, String>,
|
||||||
body_json: &Value,
|
body_json: &Value,
|
||||||
@@ -116,7 +130,7 @@ mod tests {
|
|||||||
build_generated_tool_call_id, build_local_success_background_report,
|
build_generated_tool_call_id, build_local_success_background_report,
|
||||||
build_local_success_conversion_background_report, canonicalize_tool_arguments,
|
build_local_success_conversion_background_report, canonicalize_tool_arguments,
|
||||||
prepare_local_success_response_parts, prepare_local_success_response_parts_owned,
|
prepare_local_success_response_parts, prepare_local_success_response_parts_owned,
|
||||||
LocalSyncReportParts,
|
remove_empty_pages_from_tool_arguments, LocalSyncReportParts,
|
||||||
};
|
};
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
@@ -134,6 +148,24 @@ mod tests {
|
|||||||
assert_eq!(canonicalize_tool_arguments(None), "{}");
|
assert_eq!(canonicalize_tool_arguments(None), "{}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn removes_empty_pages_from_tool_arguments() {
|
||||||
|
assert_eq!(
|
||||||
|
remove_empty_pages_from_tool_arguments(
|
||||||
|
r#"{"file_path":"/tmp/a.txt","offset":1,"limit":20,"pages":""}"#
|
||||||
|
),
|
||||||
|
r#"{"file_path":"/tmp/a.txt","offset":1,"limit":20}"#
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
remove_empty_pages_from_tool_arguments(r#"{"pages":"1-2"}"#),
|
||||||
|
r#"{"pages":"1-2"}"#
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
remove_empty_pages_from_tool_arguments(r#"{"pages":"#),
|
||||||
|
r#"{"pages":"#
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn prepare_local_success_response_parts_normalizes_headers() {
|
fn prepare_local_success_response_parts_normalizes_headers() {
|
||||||
let headers = BTreeMap::from([
|
let headers = BTreeMap::from([
|
||||||
+3
-3
@@ -2,9 +2,9 @@ use base64::Engine as _;
|
|||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
|
||||||
use crate::contracts::OPENAI_IMAGE_SYNC_FINALIZE_REPORT_KIND;
|
use crate::contracts::OPENAI_IMAGE_SYNC_FINALIZE_REPORT_KIND;
|
||||||
use crate::finalize::sse::encode_json_sse;
|
use crate::request::standard::CODEX_OPENAI_IMAGE_DEFAULT_OUTPUT_FORMAT;
|
||||||
use crate::finalize::AiSurfaceFinalizeError;
|
use crate::response::sse::encode_json_sse;
|
||||||
use crate::planner::standard::CODEX_OPENAI_IMAGE_DEFAULT_OUTPUT_FORMAT;
|
use crate::response::AiSurfaceFinalizeError;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct OpenAiImageStreamState {
|
pub struct OpenAiImageStreamState {
|
||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
|
||||||
use crate::finalize::AiSurfaceFinalizeError;
|
use crate::response::AiSurfaceFinalizeError;
|
||||||
|
|
||||||
pub fn map_claude_stop_reason(
|
pub fn map_claude_stop_reason(
|
||||||
stop_reason: Option<&str>,
|
stop_reason: Option<&str>,
|
||||||
+44
-4
@@ -2,10 +2,13 @@ use std::collections::BTreeMap;
|
|||||||
|
|
||||||
use serde_json::{json, Map, Value};
|
use serde_json::{json, Map, Value};
|
||||||
|
|
||||||
use crate::finalize::common::{build_generated_tool_call_id, canonicalize_tool_arguments};
|
use crate::response::common::{
|
||||||
use crate::finalize::sse::{encode_json_sse, map_claude_stop_reason};
|
build_generated_tool_call_id, canonicalize_tool_arguments,
|
||||||
use crate::finalize::standard::stream_core::common::*;
|
remove_empty_pages_from_tool_arguments,
|
||||||
use crate::finalize::AiSurfaceFinalizeError;
|
};
|
||||||
|
use crate::response::sse::{encode_json_sse, map_claude_stop_reason};
|
||||||
|
use crate::response::standard::stream_core::common::*;
|
||||||
|
use crate::response::AiSurfaceFinalizeError;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct ClaudeProviderToolState {
|
struct ClaudeProviderToolState {
|
||||||
@@ -658,6 +661,10 @@ impl ClaudeClientEmitter {
|
|||||||
Ok(out)
|
Ok(out)
|
||||||
}
|
}
|
||||||
CanonicalStreamEvent::ToolCallArgumentsDelta { index, arguments } => {
|
CanonicalStreamEvent::ToolCallArgumentsDelta { index, arguments } => {
|
||||||
|
let arguments = remove_empty_pages_from_tool_arguments(&arguments);
|
||||||
|
if arguments.is_empty() {
|
||||||
|
return Ok(Vec::new());
|
||||||
|
}
|
||||||
let mut out = self.ensure_started()?;
|
let mut out = self.ensure_started()?;
|
||||||
let state = self.tool_states.entry(index).or_default();
|
let state = self.tool_states.entry(index).or_default();
|
||||||
let call_id = if state.call_id.is_empty() {
|
let call_id = if state.call_id.is_empty() {
|
||||||
@@ -1195,6 +1202,39 @@ mod tests {
|
|||||||
assert!(sse.contains("\"usage\":{\"input_tokens\":0,\"output_tokens\":0}"));
|
assert!(sse.contains("\"usage\":{\"input_tokens\":0,\"output_tokens\":0}"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn claude_client_emitter_removes_empty_pages_from_tool_arguments() {
|
||||||
|
let mut emitter = ClaudeClientEmitter::default();
|
||||||
|
let mut bytes = emitter
|
||||||
|
.emit(CanonicalStreamFrame {
|
||||||
|
id: "msg_123".to_string(),
|
||||||
|
model: "claude-sonnet-4-5".to_string(),
|
||||||
|
event: CanonicalStreamEvent::ToolCallStart {
|
||||||
|
index: 0,
|
||||||
|
call_id: "toolu_read".to_string(),
|
||||||
|
name: "Read".to_string(),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.expect("tool start should encode");
|
||||||
|
bytes.extend(
|
||||||
|
emitter
|
||||||
|
.emit(CanonicalStreamFrame {
|
||||||
|
id: "msg_123".to_string(),
|
||||||
|
model: "claude-sonnet-4-5".to_string(),
|
||||||
|
event: CanonicalStreamEvent::ToolCallArgumentsDelta {
|
||||||
|
index: 0,
|
||||||
|
arguments: r#"{"file_path":"/tmp/a.txt","offset":1,"limit":20,"pages":""}"#
|
||||||
|
.to_string(),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.expect("tool delta should encode"),
|
||||||
|
);
|
||||||
|
|
||||||
|
let sse = String::from_utf8(bytes).expect("sse should be utf8");
|
||||||
|
assert!(sse.contains("\"partial_json\":\"{\\\"file_path\\\":\\\"/tmp/a.txt\\\",\\\"offset\\\":1,\\\"limit\\\":20}\""));
|
||||||
|
assert!(!sse.contains("\\\"pages\\\":\\\"\\\""));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn claude_client_emitter_injects_default_usage_into_finish_events() {
|
fn claude_client_emitter_injects_default_usage_into_finish_events() {
|
||||||
let mut emitter = ClaudeClientEmitter::default();
|
let mut emitter = ClaudeClientEmitter::default();
|
||||||
+4
-4
@@ -2,10 +2,10 @@ use std::collections::BTreeMap;
|
|||||||
|
|
||||||
use serde_json::{json, Map, Value};
|
use serde_json::{json, Map, Value};
|
||||||
|
|
||||||
use crate::finalize::common::{build_generated_tool_call_id, canonicalize_tool_arguments};
|
use crate::response::common::{build_generated_tool_call_id, canonicalize_tool_arguments};
|
||||||
use crate::finalize::sse::encode_json_sse;
|
use crate::response::sse::encode_json_sse;
|
||||||
use crate::finalize::standard::stream_core::common::*;
|
use crate::response::standard::stream_core::common::*;
|
||||||
use crate::finalize::AiSurfaceFinalizeError;
|
use crate::response::AiSurfaceFinalizeError;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct GeminiProviderToolState {
|
struct GeminiProviderToolState {
|
||||||
+4
-4
@@ -2,10 +2,10 @@ use std::collections::BTreeMap;
|
|||||||
|
|
||||||
use serde_json::{json, Map, Value};
|
use serde_json::{json, Map, Value};
|
||||||
|
|
||||||
use crate::finalize::common::build_generated_tool_call_id;
|
use crate::response::common::build_generated_tool_call_id;
|
||||||
use crate::finalize::sse::{encode_done_sse, encode_json_sse};
|
use crate::response::sse::{encode_done_sse, encode_json_sse};
|
||||||
use crate::finalize::standard::stream_core::common::*;
|
use crate::response::standard::stream_core::common::*;
|
||||||
use crate::finalize::AiSurfaceFinalizeError;
|
use crate::response::AiSurfaceFinalizeError;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct OpenAIChatProviderToolState {
|
struct OpenAIChatProviderToolState {
|
||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
use serde_json::{json, Map, Value};
|
use serde_json::{json, Map, Value};
|
||||||
|
|
||||||
pub use aether_ai_formats::stream::{
|
pub use aether_ai_formats::protocol::stream::{
|
||||||
CanonicalContentPart, CanonicalStreamEvent, CanonicalStreamFrame, CanonicalUsage,
|
CanonicalContentPart, CanonicalStreamEvent, CanonicalStreamFrame, CanonicalUsage,
|
||||||
};
|
};
|
||||||
|
|
||||||
+7
-7
@@ -2,20 +2,20 @@ use aether_ai_formats::FormatId;
|
|||||||
use aether_contracts::{ExecutionStreamTerminalSummary, StandardizedUsage};
|
use aether_contracts::{ExecutionStreamTerminalSummary, StandardizedUsage};
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
|
||||||
use crate::finalize::error_body::{
|
use crate::response::error_body::{
|
||||||
build_core_error_body_for_client_format, LocalCoreSyncErrorKind,
|
build_core_error_body_for_client_format, LocalCoreSyncErrorKind,
|
||||||
};
|
};
|
||||||
use crate::finalize::sse::encode_json_sse;
|
use crate::response::sse::encode_json_sse;
|
||||||
use crate::finalize::standard::claude::stream::{ClaudeClientEmitter, ClaudeProviderState};
|
use crate::response::standard::claude::stream::{ClaudeClientEmitter, ClaudeProviderState};
|
||||||
use crate::finalize::standard::gemini::stream::{GeminiClientEmitter, GeminiProviderState};
|
use crate::response::standard::gemini::stream::{GeminiClientEmitter, GeminiProviderState};
|
||||||
use crate::finalize::standard::openai::stream::{
|
use crate::response::standard::openai::stream::{
|
||||||
OpenAIChatClientEmitter, OpenAIChatProviderState, OpenAIResponsesClientEmitter,
|
OpenAIChatClientEmitter, OpenAIChatProviderState, OpenAIResponsesClientEmitter,
|
||||||
OpenAIResponsesProviderState,
|
OpenAIResponsesProviderState,
|
||||||
};
|
};
|
||||||
use crate::finalize::standard::stream_core::common::{
|
use crate::response::standard::stream_core::common::{
|
||||||
decode_json_data_line, CanonicalStreamEvent, CanonicalStreamFrame, CanonicalUsage,
|
decode_json_data_line, CanonicalStreamEvent, CanonicalStreamFrame, CanonicalUsage,
|
||||||
};
|
};
|
||||||
use crate::finalize::AiSurfaceFinalizeError;
|
use crate::response::AiSurfaceFinalizeError;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct StreamingStandardFormatMatrix {
|
pub struct StreamingStandardFormatMatrix {
|
||||||
+6
-6
@@ -1,13 +1,13 @@
|
|||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
|
||||||
use crate::adaptation::kiro_stream::KiroToClaudeCliStreamState;
|
use crate::provider_compat::kiro_stream::KiroToClaudeCliStreamState;
|
||||||
use crate::adaptation::private_envelope::transform_provider_private_stream_line;
|
use crate::provider_compat::private_envelope::transform_provider_private_stream_line;
|
||||||
use crate::adaptation::surfaces::{
|
use crate::provider_compat::surfaces::{
|
||||||
provider_adaptation_should_unwrap_stream_envelope, KIRO_ENVELOPE_NAME,
|
provider_adaptation_should_unwrap_stream_envelope, KIRO_ENVELOPE_NAME,
|
||||||
};
|
};
|
||||||
use crate::finalize::openai_image_stream::OpenAiImageStreamState;
|
use crate::response::openai_image_stream::OpenAiImageStreamState;
|
||||||
use crate::finalize::standard::stream_core::StreamingStandardFormatMatrix;
|
use crate::response::standard::stream_core::StreamingStandardFormatMatrix;
|
||||||
use crate::finalize::AiSurfaceFinalizeError;
|
use crate::response::AiSurfaceFinalizeError;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum FinalizeStreamRewriteMode {
|
pub enum FinalizeStreamRewriteMode {
|
||||||
+38
-7
@@ -1,13 +1,13 @@
|
|||||||
use base64::Engine as _;
|
use base64::Engine as _;
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
use aether_ai_formats::conversion::response::{
|
use aether_ai_formats::protocol::conversion::response::{
|
||||||
convert_claude_response_to_openai_responses, convert_gemini_chat_response_to_openai_chat,
|
convert_claude_response_to_openai_responses, convert_gemini_chat_response_to_openai_chat,
|
||||||
convert_openai_chat_response_to_claude_chat, convert_openai_chat_response_to_gemini_chat,
|
convert_openai_chat_response_to_claude_chat, convert_openai_chat_response_to_gemini_chat,
|
||||||
convert_openai_chat_response_to_openai_responses,
|
convert_openai_chat_response_to_openai_responses,
|
||||||
convert_openai_responses_response_to_openai_chat,
|
convert_openai_responses_response_to_openai_chat,
|
||||||
};
|
};
|
||||||
use aether_ai_formats::registry::{convert_response, FormatContext};
|
use aether_ai_formats::protocol::registry::{convert_response, FormatContext};
|
||||||
use aether_ai_formats::{
|
use aether_ai_formats::{
|
||||||
canonical_to_claude_response, canonical_to_gemini_response, canonical_to_openai_chat_response,
|
canonical_to_claude_response, canonical_to_gemini_response, canonical_to_openai_chat_response,
|
||||||
canonical_to_openai_responses_compact_response, canonical_to_openai_responses_response,
|
canonical_to_openai_responses_compact_response, canonical_to_openai_responses_response,
|
||||||
@@ -18,8 +18,9 @@ use aether_ai_formats::{
|
|||||||
use serde_json::{json, Map, Value};
|
use serde_json::{json, Map, Value};
|
||||||
|
|
||||||
use super::AiSurfaceFinalizeError;
|
use super::AiSurfaceFinalizeError;
|
||||||
use crate::finalize::standard::gemini::stream::GeminiProviderState;
|
use crate::response::common::remove_empty_pages_from_tool_arguments;
|
||||||
use crate::finalize::standard::stream_core::common::{
|
use crate::response::standard::gemini::stream::GeminiProviderState;
|
||||||
|
use crate::response::standard::stream_core::common::{
|
||||||
map_openai_finish_reason_to_gemini, parse_json_arguments_value, CanonicalContentPart,
|
map_openai_finish_reason_to_gemini, parse_json_arguments_value, CanonicalContentPart,
|
||||||
CanonicalStreamEvent, CanonicalUsage,
|
CanonicalStreamEvent, CanonicalUsage,
|
||||||
};
|
};
|
||||||
@@ -2363,8 +2364,9 @@ pub fn aggregate_claude_stream_sync_response(body: &[u8]) -> Option<Value> {
|
|||||||
}
|
}
|
||||||
"tool_use" => {
|
"tool_use" => {
|
||||||
if !state.partial_json.is_empty() {
|
if !state.partial_json.is_empty() {
|
||||||
let input = serde_json::from_str::<Value>(&state.partial_json)
|
let arguments = remove_empty_pages_from_tool_arguments(&state.partial_json);
|
||||||
.unwrap_or(Value::String(state.partial_json));
|
let input = serde_json::from_str::<Value>(&arguments)
|
||||||
|
.unwrap_or(Value::String(arguments));
|
||||||
block.insert("input".to_string(), input);
|
block.insert("input".to_string(), input);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2873,7 +2875,7 @@ mod tests {
|
|||||||
maybe_build_standard_sync_finalize_product_from_normalized_payload,
|
maybe_build_standard_sync_finalize_product_from_normalized_payload,
|
||||||
StandardSyncFinalizeNormalizedProduct,
|
StandardSyncFinalizeNormalizedProduct,
|
||||||
};
|
};
|
||||||
use aether_ai_formats::conversion::response::{
|
use aether_ai_formats::protocol::conversion::response::{
|
||||||
convert_claude_chat_response_to_openai_chat, convert_gemini_chat_response_to_openai_chat,
|
convert_claude_chat_response_to_openai_chat, convert_gemini_chat_response_to_openai_chat,
|
||||||
convert_openai_chat_response_to_claude_chat, convert_openai_chat_response_to_gemini_chat,
|
convert_openai_chat_response_to_claude_chat, convert_openai_chat_response_to_gemini_chat,
|
||||||
convert_openai_chat_response_to_openai_responses,
|
convert_openai_chat_response_to_openai_responses,
|
||||||
@@ -2909,6 +2911,35 @@ mod tests {
|
|||||||
assert_eq!(aggregated["usage"]["output_tokens"], 2);
|
assert_eq!(aggregated["usage"]["output_tokens"], 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn aggregates_claude_stream_removes_empty_pages_from_tool_input() {
|
||||||
|
let body = concat!(
|
||||||
|
"event: message_start\n",
|
||||||
|
"data: {\"type\":\"message_start\",\"message\":{\"id\":\"msg_123\",\"type\":\"message\",\"role\":\"assistant\",\"model\":\"claude-sonnet-4-5\",\"content\":[],\"stop_reason\":null,\"stop_sequence\":null}}\n\n",
|
||||||
|
"event: content_block_start\n",
|
||||||
|
"data: {\"type\":\"content_block_start\",\"index\":0,\"content_block\":{\"type\":\"tool_use\",\"id\":\"toolu_read\",\"name\":\"Read\",\"input\":{}}}\n\n",
|
||||||
|
"event: content_block_delta\n",
|
||||||
|
"data: {\"type\":\"content_block_delta\",\"index\":0,\"delta\":{\"type\":\"input_json_delta\",\"partial_json\":\"{\\\"file_path\\\":\\\"/tmp/a.txt\\\",\\\"offset\\\":1,\\\"limit\\\":20,\\\"pages\\\":\\\"\\\"}\"}}\n\n",
|
||||||
|
"event: content_block_stop\n",
|
||||||
|
"data: {\"type\":\"content_block_stop\",\"index\":0}\n\n",
|
||||||
|
"event: message_stop\n",
|
||||||
|
"data: {\"type\":\"message_stop\"}\n\n",
|
||||||
|
);
|
||||||
|
|
||||||
|
let aggregated =
|
||||||
|
aggregate_claude_stream_sync_response(body.as_bytes()).expect("body should aggregate");
|
||||||
|
|
||||||
|
assert_eq!(aggregated["content"][0]["type"], "tool_use");
|
||||||
|
assert_eq!(
|
||||||
|
aggregated["content"][0]["input"],
|
||||||
|
json!({
|
||||||
|
"file_path": "/tmp/a.txt",
|
||||||
|
"offset": 1,
|
||||||
|
"limit": 20,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn aggregates_gemini_stream_deltas_media_and_signatures_into_sync_body() {
|
fn aggregates_gemini_stream_deltas_media_and_signatures_into_sync_body() {
|
||||||
let body = concat!(
|
let body = concat!(
|
||||||
+7
-7
@@ -1,18 +1,18 @@
|
|||||||
use aether_ai_formats::conversion::response::{
|
use aether_ai_formats::protocol::conversion::response::{
|
||||||
convert_claude_response_to_openai_responses, convert_gemini_response_to_openai_responses,
|
convert_claude_response_to_openai_responses, convert_gemini_response_to_openai_responses,
|
||||||
convert_openai_chat_response_to_openai_responses,
|
convert_openai_chat_response_to_openai_responses,
|
||||||
};
|
};
|
||||||
use aether_contracts::{ExecutionStreamTerminalSummary, StandardizedUsage};
|
use aether_contracts::{ExecutionStreamTerminalSummary, StandardizedUsage};
|
||||||
use serde_json::{json, Value};
|
use serde_json::{json, Value};
|
||||||
|
|
||||||
use crate::finalize::sse::encode_json_sse;
|
use crate::response::sse::encode_json_sse;
|
||||||
use crate::finalize::standard::claude::stream::ClaudeClientEmitter;
|
use crate::response::standard::claude::stream::ClaudeClientEmitter;
|
||||||
use crate::finalize::standard::gemini::stream::GeminiClientEmitter;
|
use crate::response::standard::gemini::stream::GeminiClientEmitter;
|
||||||
use crate::finalize::standard::openai::stream::{
|
use crate::response::standard::openai::stream::{
|
||||||
OpenAIChatClientEmitter, OpenAIResponsesClientEmitter, OpenAIResponsesProviderState,
|
OpenAIChatClientEmitter, OpenAIResponsesClientEmitter, OpenAIResponsesProviderState,
|
||||||
};
|
};
|
||||||
use crate::finalize::standard::stream_core::CanonicalStreamFrame;
|
use crate::response::standard::stream_core::CanonicalStreamFrame;
|
||||||
use crate::finalize::AiSurfaceFinalizeError;
|
use crate::response::AiSurfaceFinalizeError;
|
||||||
|
|
||||||
pub struct SyncToStreamBridgeOutcome {
|
pub struct SyncToStreamBridgeOutcome {
|
||||||
pub sse_body: Vec<u8>,
|
pub sse_body: Vec<u8>,
|
||||||
@@ -8,7 +8,6 @@ description = "AI serving application contracts and ports for Aether"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
aether-ai-formats.workspace = true
|
aether-ai-formats.workspace = true
|
||||||
aether-ai-surfaces.workspace = true
|
|
||||||
aether-contracts.workspace = true
|
aether-contracts.workspace = true
|
||||||
aether-scheduler-core.workspace = true
|
aether-scheduler-core.workspace = true
|
||||||
async-trait.workspace = true
|
async-trait.workspace = true
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
use aether_ai_surfaces::api::ExecutionRuntimeAuthContext;
|
use aether_ai_formats::api::ExecutionRuntimeAuthContext;
|
||||||
use aether_contracts::{ExecutionPlan, RequestBody};
|
use aether_contracts::{ExecutionPlan, RequestBody};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user