mirror of
https://github.com/fawney19/Aether.git
synced 2026-10-05 17:07:46 +08:00
feat(openai): unify tier authorization and settlement
This commit is contained in:
@@ -185,6 +185,9 @@ mod tests {
|
||||
"reasoning": { "effort": "max" },
|
||||
"service_tier": "priority"
|
||||
})),
|
||||
request_metadata: Some(serde_json::json!({
|
||||
"provider_actual_service_tier": "default"
|
||||
})),
|
||||
..UsageEventData::default()
|
||||
},
|
||||
})
|
||||
@@ -210,6 +213,14 @@ mod tests {
|
||||
.and_then(serde_json::Value::as_str),
|
||||
Some("priority")
|
||||
);
|
||||
assert_eq!(
|
||||
record
|
||||
.request_metadata
|
||||
.as_ref()
|
||||
.and_then(|value| value.get("provider_actual_service_tier"))
|
||||
.and_then(serde_json::Value::as_str),
|
||||
Some("default")
|
||||
);
|
||||
assert_eq!(record.finalized_at_unix_secs, Some(1_700_000_000));
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,9 @@ use aether_ai_formats::api::{
|
||||
use aether_ai_formats::UPSTREAM_IS_STREAM_KEY;
|
||||
use aether_contracts::ExecutionPlan;
|
||||
use aether_data_contracts::repository::usage::{
|
||||
extract_provider_actual_service_tier_from_response,
|
||||
extract_provider_reasoning_effort_from_body, extract_provider_service_tier_from_body,
|
||||
normalize_provider_service_tier, PROVIDER_ACTUAL_SERVICE_TIER_METADATA_KEY,
|
||||
PROVIDER_REASONING_EFFORT_METADATA_KEY, PROVIDER_SERVICE_TIER_METADATA_KEY,
|
||||
};
|
||||
use serde_json::{json, Map, Value};
|
||||
@@ -106,6 +108,44 @@ pub(crate) fn attach_provider_request_body_metadata(
|
||||
(!object.is_empty()).then_some(Value::Object(object))
|
||||
}
|
||||
|
||||
pub(crate) fn attach_provider_response_body_metadata(
|
||||
metadata: Option<Value>,
|
||||
provider_response_body: Option<&Value>,
|
||||
) -> Option<Value> {
|
||||
if metadata
|
||||
.as_ref()
|
||||
.and_then(Value::as_object)
|
||||
.and_then(|object| object.get(PROVIDER_ACTUAL_SERVICE_TIER_METADATA_KEY))
|
||||
.and_then(Value::as_str)
|
||||
.and_then(normalize_provider_service_tier)
|
||||
.is_some()
|
||||
{
|
||||
return metadata;
|
||||
}
|
||||
let actual_service_tier =
|
||||
extract_provider_actual_service_tier_from_response(provider_response_body);
|
||||
attach_provider_actual_service_tier_metadata(metadata, actual_service_tier.as_deref())
|
||||
}
|
||||
|
||||
pub(crate) fn attach_provider_actual_service_tier_metadata(
|
||||
metadata: Option<Value>,
|
||||
actual_service_tier: Option<&str>,
|
||||
) -> Option<Value> {
|
||||
let Some(actual_service_tier) = actual_service_tier.and_then(normalize_provider_service_tier)
|
||||
else {
|
||||
return metadata;
|
||||
};
|
||||
let mut object = match metadata {
|
||||
Some(Value::Object(object)) => object,
|
||||
_ => Map::new(),
|
||||
};
|
||||
object.insert(
|
||||
PROVIDER_ACTUAL_SERVICE_TIER_METADATA_KEY.to_string(),
|
||||
Value::String(actual_service_tier),
|
||||
);
|
||||
(!object.is_empty()).then_some(Value::Object(object))
|
||||
}
|
||||
|
||||
fn copy_allowed_metadata_fields(source: &Map<String, Value>, target: &mut Map<String, Value>) {
|
||||
copy_non_empty_string(source, target, "trace_id");
|
||||
copy_non_empty_string(source, target, "client_ip");
|
||||
@@ -120,6 +160,7 @@ fn copy_allowed_metadata_fields(source: &Map<String, Value>, target: &mut Map<St
|
||||
copy_non_empty_string(source, target, "request_path_and_query");
|
||||
copy_non_empty_string(source, target, PROVIDER_REASONING_EFFORT_METADATA_KEY);
|
||||
copy_non_empty_string(source, target, PROVIDER_SERVICE_TIER_METADATA_KEY);
|
||||
copy_non_empty_string(source, target, PROVIDER_ACTUAL_SERVICE_TIER_METADATA_KEY);
|
||||
copy_number(source, target, "provider_request_body_base64_bytes");
|
||||
copy_number(source, target, "provider_response_body_base64_bytes");
|
||||
copy_number(source, target, "client_response_body_base64_bytes");
|
||||
@@ -165,6 +206,11 @@ fn move_allowed_metadata_fields(mut source: Map<String, Value>, target: &mut Map
|
||||
remove_non_empty_string(&mut source, target, "request_path_and_query");
|
||||
remove_non_empty_string(&mut source, target, PROVIDER_REASONING_EFFORT_METADATA_KEY);
|
||||
remove_non_empty_string(&mut source, target, PROVIDER_SERVICE_TIER_METADATA_KEY);
|
||||
remove_non_empty_string(
|
||||
&mut source,
|
||||
target,
|
||||
PROVIDER_ACTUAL_SERVICE_TIER_METADATA_KEY,
|
||||
);
|
||||
remove_number(&mut source, target, "provider_request_body_base64_bytes");
|
||||
remove_number(&mut source, target, "provider_response_body_base64_bytes");
|
||||
remove_number(&mut source, target, "client_response_body_base64_bytes");
|
||||
@@ -449,7 +495,8 @@ mod tests {
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use super::{
|
||||
attach_provider_request_body_metadata, build_usage_request_metadata_seed,
|
||||
attach_provider_actual_service_tier_metadata, attach_provider_request_body_metadata,
|
||||
attach_provider_response_body_metadata, build_usage_request_metadata_seed,
|
||||
merge_usage_request_metadata, merge_usage_request_metadata_owned,
|
||||
sanitize_usage_request_metadata, sanitize_usage_request_metadata_ref,
|
||||
MAX_USAGE_REQUEST_METADATA_BYTES, MAX_USAGE_REQUEST_METADATA_DEPTH,
|
||||
@@ -803,6 +850,59 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn provider_response_metadata_preserves_terminal_actual_service_tier() {
|
||||
let metadata = attach_provider_response_body_metadata(
|
||||
Some(json!({"provider_service_tier": "priority"})),
|
||||
Some(&json!({
|
||||
"chunks": [
|
||||
{"service_tier": "priority"},
|
||||
{"service_tier": "Default", "usage": {"total_tokens": 12}}
|
||||
]
|
||||
})),
|
||||
)
|
||||
.expect("requested and actual provider tiers should be preserved");
|
||||
|
||||
assert_eq!(
|
||||
metadata,
|
||||
json!({
|
||||
"provider_service_tier": "priority",
|
||||
"provider_actual_service_tier": "default"
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn terminal_summary_tier_uses_the_same_normalized_metadata_field() {
|
||||
let metadata = attach_provider_actual_service_tier_metadata(
|
||||
Some(json!({"trace_id": "trace-1"})),
|
||||
Some(" Flex "),
|
||||
)
|
||||
.expect("terminal summary tier should be retained");
|
||||
|
||||
assert_eq!(
|
||||
metadata,
|
||||
json!({
|
||||
"trace_id": "trace-1",
|
||||
"provider_actual_service_tier": "flex"
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn terminal_summary_tier_precedes_truncated_response_capture() {
|
||||
let metadata = attach_provider_response_body_metadata(
|
||||
Some(json!({"provider_actual_service_tier": "default"})),
|
||||
Some(&json!({"chunks": [{"service_tier": "priority"}]})),
|
||||
)
|
||||
.expect("terminal summary tier should remain");
|
||||
|
||||
assert_eq!(
|
||||
metadata.get("provider_actual_service_tier"),
|
||||
Some(&Value::String("default".to_string()))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn owned_merge_matches_filtered_merge_for_trusted_objects() {
|
||||
let base = Some(json!({
|
||||
@@ -811,7 +911,8 @@ mod tests {
|
||||
}));
|
||||
let override_value = Some(json!({
|
||||
"billing_snapshot_status": "complete",
|
||||
"trace_id": "trace-2"
|
||||
"trace_id": "trace-2",
|
||||
"provider_actual_service_tier": "default"
|
||||
}));
|
||||
|
||||
assert_eq!(
|
||||
|
||||
@@ -13,6 +13,7 @@ use tokio::sync::mpsc;
|
||||
use tracing::{info, warn};
|
||||
|
||||
use crate::executor::spawn_on_usage_background_runtime;
|
||||
use crate::request_metadata::attach_provider_response_body_metadata;
|
||||
use crate::worker::{
|
||||
build_usage_queue_worker_with_record_gate, UsageWorkerControl, UsageWorkerObservation,
|
||||
};
|
||||
@@ -921,6 +922,7 @@ impl UsageRuntime {
|
||||
where
|
||||
T: UsageRuntimeAccess,
|
||||
{
|
||||
preserve_provider_response_facts(event);
|
||||
match self.cached_body_capture_policy(data).await {
|
||||
Ok(policy) => apply_usage_body_capture_policy_to_event(policy, event),
|
||||
Err(err) => {
|
||||
@@ -1200,6 +1202,12 @@ impl UsageRuntime {
|
||||
}
|
||||
}
|
||||
|
||||
fn preserve_provider_response_facts(event: &mut UsageEvent) {
|
||||
let metadata = event.data.request_metadata.take();
|
||||
event.data.request_metadata =
|
||||
attach_provider_response_body_metadata(metadata, event.data.response_body.as_ref());
|
||||
}
|
||||
|
||||
impl UsageQueueHealthSnapshot {
|
||||
fn apply_stream_stats(&mut self, stats: RuntimeQueueStats) {
|
||||
self.stream_length = stats.stream_length;
|
||||
@@ -2318,8 +2326,9 @@ mod tests {
|
||||
use tokio::time::{sleep, Duration};
|
||||
|
||||
use super::{
|
||||
UsageBillingEventEnricher, UsageBodyCapturePolicy, UsageRequestRecordLevel,
|
||||
UsageRuntimeAccess, UsageWorkerObservation, UsageWorkerSupervisorState,
|
||||
preserve_provider_response_facts, UsageBillingEventEnricher, UsageBodyCapturePolicy,
|
||||
UsageRequestRecordLevel, UsageRuntimeAccess, UsageWorkerObservation,
|
||||
UsageWorkerSupervisorState,
|
||||
};
|
||||
use crate::worker::ManualProxyNodeCounter;
|
||||
use crate::{
|
||||
@@ -4010,16 +4019,21 @@ mod tests {
|
||||
provider_request_body_ref: Some(
|
||||
"usage://request/req-basic-1/provider_request_body".to_string(),
|
||||
),
|
||||
response_body: Some(json!({"error":{"message":"bad gateway"}})),
|
||||
response_body: Some(json!({
|
||||
"error":{"message":"bad gateway"},
|
||||
"service_tier": "Default"
|
||||
})),
|
||||
response_body_ref: Some("usage://request/req-basic-1/response_body".to_string()),
|
||||
client_response_body: Some(json!({"detail":"bad gateway"})),
|
||||
client_response_body_ref: Some(
|
||||
"usage://request/req-basic-1/client_response_body".to_string(),
|
||||
),
|
||||
request_metadata: Some(json!({"provider_service_tier": "priority"})),
|
||||
..UsageEventData::default()
|
||||
},
|
||||
);
|
||||
|
||||
preserve_provider_response_facts(&mut event);
|
||||
apply_usage_body_capture_policy_to_event(
|
||||
UsageBodyCapturePolicy {
|
||||
record_level: UsageRequestRecordLevel::Basic,
|
||||
@@ -4038,5 +4052,14 @@ mod tests {
|
||||
assert!(event.data.response_body_ref.is_none());
|
||||
assert!(event.data.client_response_body.is_none());
|
||||
assert!(event.data.client_response_body_ref.is_none());
|
||||
assert_eq!(
|
||||
event
|
||||
.data
|
||||
.request_metadata
|
||||
.as_ref()
|
||||
.and_then(|metadata| metadata.get("provider_actual_service_tier"))
|
||||
.and_then(serde_json::Value::as_str),
|
||||
Some("default")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,8 @@ use crate::body_capture::{
|
||||
RuntimeBodyCaptureMetadataInput,
|
||||
};
|
||||
use crate::request_metadata::{
|
||||
attach_provider_request_body_metadata, build_usage_request_metadata_seed,
|
||||
attach_provider_actual_service_tier_metadata, attach_provider_request_body_metadata,
|
||||
attach_provider_response_body_metadata, build_usage_request_metadata_seed,
|
||||
merge_usage_request_metadata, merge_usage_request_metadata_owned,
|
||||
sanitize_usage_request_metadata, sanitize_usage_request_metadata_ref,
|
||||
};
|
||||
@@ -163,6 +164,7 @@ pub struct StreamTerminalUsagePayloadSeed {
|
||||
pub client_response: Option<Value>,
|
||||
pub client_response_body_state: Option<UsageBodyCaptureState>,
|
||||
pub standardized_usage: Option<StandardizedUsage>,
|
||||
pub provider_actual_service_tier: Option<String>,
|
||||
pub observed_stream_finish: Option<bool>,
|
||||
pub terminal_error_message: Option<String>,
|
||||
pub capture_metadata: Option<Value>,
|
||||
@@ -965,6 +967,10 @@ pub fn build_stream_terminal_usage_payload_seed(
|
||||
.terminal_summary
|
||||
.as_ref()
|
||||
.and_then(|summary| summary.standardized_usage.clone()),
|
||||
provider_actual_service_tier: payload
|
||||
.terminal_summary
|
||||
.as_ref()
|
||||
.and_then(|summary| summary.provider_actual_service_tier.clone()),
|
||||
observed_stream_finish,
|
||||
terminal_error_message,
|
||||
capture_metadata: build_payload_body_capture_metadata(
|
||||
@@ -1004,6 +1010,10 @@ pub fn build_sync_terminal_usage_seed(
|
||||
status_code,
|
||||
provider_response_full.as_ref(),
|
||||
);
|
||||
let request_metadata = attach_provider_response_body_metadata(
|
||||
context_seed.request_metadata,
|
||||
provider_response_full.as_ref(),
|
||||
);
|
||||
|
||||
TerminalUsageSeed {
|
||||
terminal_state,
|
||||
@@ -1046,7 +1056,7 @@ pub fn build_sync_terminal_usage_seed(
|
||||
provider_response: provider_response_full,
|
||||
client_response_headers,
|
||||
client_response,
|
||||
request_metadata: context_seed.request_metadata,
|
||||
request_metadata,
|
||||
audit_payload: capture_metadata,
|
||||
standardized_usage,
|
||||
}
|
||||
@@ -1088,6 +1098,7 @@ pub fn build_stream_terminal_usage_seed(
|
||||
mut client_response,
|
||||
mut client_response_body_state,
|
||||
standardized_usage,
|
||||
provider_actual_service_tier,
|
||||
observed_stream_finish,
|
||||
terminal_error_message,
|
||||
capture_metadata,
|
||||
@@ -1177,6 +1188,12 @@ pub fn build_stream_terminal_usage_seed(
|
||||
missing_observed_finish,
|
||||
terminal_error_message.is_some(),
|
||||
);
|
||||
let request_metadata = attach_provider_actual_service_tier_metadata(
|
||||
context_seed.request_metadata,
|
||||
provider_actual_service_tier.as_deref(),
|
||||
);
|
||||
let request_metadata =
|
||||
attach_provider_response_body_metadata(request_metadata, provider_response_full.as_ref());
|
||||
|
||||
TerminalUsageSeed {
|
||||
terminal_state,
|
||||
@@ -1219,7 +1236,7 @@ pub fn build_stream_terminal_usage_seed(
|
||||
provider_response: provider_response_full,
|
||||
client_response_headers,
|
||||
client_response,
|
||||
request_metadata: context_seed.request_metadata,
|
||||
request_metadata,
|
||||
audit_payload: capture_metadata,
|
||||
standardized_usage,
|
||||
}
|
||||
@@ -4588,7 +4605,7 @@ mod tests {
|
||||
finish_reason: Some("stop".to_string()),
|
||||
response_id: Some("resp_summary_1".to_string()),
|
||||
model: Some("gpt-5.4".to_string()),
|
||||
provider_actual_service_tier: None,
|
||||
provider_actual_service_tier: Some("Default".to_string()),
|
||||
observed_finish: true,
|
||||
unknown_event_count: 0,
|
||||
parser_error: None,
|
||||
@@ -4607,6 +4624,15 @@ mod tests {
|
||||
assert_eq!(event.data.cache_read_input_tokens, Some(3));
|
||||
assert!(event.data.response_body.is_none());
|
||||
assert!(event.data.client_response_body.is_none());
|
||||
assert_eq!(
|
||||
event
|
||||
.data
|
||||
.request_metadata
|
||||
.as_ref()
|
||||
.and_then(|metadata| metadata.get("provider_actual_service_tier"))
|
||||
.and_then(Value::as_str),
|
||||
Some("default")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user