mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-09 20:50:20 +08:00
Merge pull request #652 from zhefox/main
fix(usage): preserve token counts in body redaction
This commit is contained in:
@@ -25,6 +25,8 @@ concurrency:
|
||||
|
||||
env:
|
||||
CARGO_INCREMENTAL: 0
|
||||
CARGO_PROFILE_DEV_DEBUG: 0
|
||||
CARGO_PROFILE_TEST_DEBUG: 0
|
||||
CARGO_TERM_COLOR: always
|
||||
|
||||
jobs:
|
||||
@@ -68,7 +70,7 @@ jobs:
|
||||
env:
|
||||
RUSTC_WRAPPER: sccache
|
||||
SCCACHE_GHA_ENABLED: "true"
|
||||
run: cargo clippy -p aether-gateway --all-targets -- -D warnings
|
||||
run: cargo clippy -p aether-gateway --lib --bins --examples -- -D warnings
|
||||
|
||||
- name: Show sccache stats
|
||||
if: always()
|
||||
@@ -184,15 +186,27 @@ jobs:
|
||||
- name: Setup sccache
|
||||
uses: mozilla-actions/sccache-action@v0.0.9
|
||||
|
||||
- name: Setup mold
|
||||
uses: rui314/setup-mold@v1
|
||||
|
||||
- name: Install nextest
|
||||
uses: taiki-e/install-action@nextest
|
||||
|
||||
- name: Test
|
||||
- name: Test lib
|
||||
env:
|
||||
RUSTC_WRAPPER: sccache
|
||||
SCCACHE_GHA_ENABLED: "true"
|
||||
RUST_MIN_STACK: "16777216"
|
||||
run: cargo nextest run -p aether-gateway
|
||||
RUSTFLAGS: "-C link-arg=-fuse-ld=mold"
|
||||
run: cargo nextest run -p aether-gateway --lib
|
||||
|
||||
- name: Test bin
|
||||
env:
|
||||
RUSTC_WRAPPER: sccache
|
||||
SCCACHE_GHA_ENABLED: "true"
|
||||
RUST_MIN_STACK: "16777216"
|
||||
RUSTFLAGS: "-C link-arg=-fuse-ld=mold"
|
||||
run: cargo nextest run -p aether-gateway --bin aether-gateway
|
||||
|
||||
- name: Show sccache stats
|
||||
if: always()
|
||||
|
||||
@@ -434,7 +434,6 @@ mod tests {
|
||||
let calls = Arc::new(AtomicUsize::new(0));
|
||||
let active = Arc::new(AtomicUsize::new(0));
|
||||
let max_active = Arc::new(AtomicUsize::new(0));
|
||||
let started = Instant::now();
|
||||
let mut tasks = Vec::new();
|
||||
|
||||
for (key, value) in [("key-a", 1_u64), ("key-b", 2_u64)] {
|
||||
@@ -471,11 +470,6 @@ mod tests {
|
||||
assert_eq!(results, vec![Some(1), Some(2)]);
|
||||
assert_eq!(calls.load(Ordering::Acquire), 2);
|
||||
assert_eq!(max_active.load(Ordering::Acquire), 2);
|
||||
assert!(
|
||||
started.elapsed() < Duration::from_millis(95),
|
||||
"different cache keys should load in parallel, elapsed={:?}",
|
||||
started.elapsed()
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
||||
@@ -2645,7 +2645,7 @@ fn is_sensitive_body_key(key: &str) -> bool {
|
||||
.filter(|ch| ch.is_ascii_alphanumeric())
|
||||
.collect::<String>()
|
||||
.to_ascii_lowercase();
|
||||
normalized.contains("token")
|
||||
is_sensitive_token_body_key(&normalized)
|
||||
|| normalized.contains("apikey")
|
||||
|| normalized.contains("password")
|
||||
|| normalized.contains("authorization")
|
||||
@@ -2653,6 +2653,33 @@ fn is_sensitive_body_key(key: &str) -> bool {
|
||||
|| normalized == "cookie"
|
||||
}
|
||||
|
||||
fn is_sensitive_token_body_key(normalized: &str) -> bool {
|
||||
if !normalized.contains("token") || is_token_quantity_body_key(normalized) {
|
||||
return false;
|
||||
}
|
||||
|
||||
normalized == "token" || normalized.ends_with("token")
|
||||
}
|
||||
|
||||
fn is_token_quantity_body_key(normalized: &str) -> bool {
|
||||
normalized.ends_with("tokens")
|
||||
|| normalized.ends_with("tokencount")
|
||||
|| normalized.ends_with("tokenlimit")
|
||||
|| matches!(
|
||||
normalized,
|
||||
"maxtoken"
|
||||
| "maxcompletiontoken"
|
||||
| "maxoutputtoken"
|
||||
| "inputtoken"
|
||||
| "outputtoken"
|
||||
| "completiontoken"
|
||||
| "prompttoken"
|
||||
| "totaltoken"
|
||||
| "reasoningtoken"
|
||||
| "cachedtoken"
|
||||
)
|
||||
}
|
||||
|
||||
fn resolve_error_category(
|
||||
status_code: u16,
|
||||
event_type: UsageEventType,
|
||||
@@ -3922,6 +3949,69 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn usage_body_capture_preserves_token_limits_and_counts() {
|
||||
let masked = mask_sensitive_body_fields(json!({
|
||||
"max_token": 4096,
|
||||
"max_tokens": 128000,
|
||||
"max_completion_tokens": 128000,
|
||||
"max_output_tokens": 64000,
|
||||
"usage": {
|
||||
"prompt_tokens": 1,
|
||||
"completion_tokens": 2,
|
||||
"total_tokens": 3,
|
||||
"promptTokenCount": 4,
|
||||
"candidatesTokenCount": 5
|
||||
},
|
||||
"generationConfig": {
|
||||
"maxOutputTokens": 8192,
|
||||
"maxOutputToken": 4096
|
||||
},
|
||||
"metadata": {
|
||||
"access_token": "secret-access-token-value",
|
||||
"authToken": "secret-auth-token-value",
|
||||
"token": "secret-token-value"
|
||||
}
|
||||
}));
|
||||
|
||||
assert_eq!(masked.get("max_token"), Some(&json!(4096)));
|
||||
assert_eq!(masked.get("max_tokens"), Some(&json!(128000)));
|
||||
assert_eq!(masked.get("max_completion_tokens"), Some(&json!(128000)));
|
||||
assert_eq!(masked.get("max_output_tokens"), Some(&json!(64000)));
|
||||
assert_eq!(masked.pointer("/usage/prompt_tokens"), Some(&json!(1)));
|
||||
assert_eq!(masked.pointer("/usage/completion_tokens"), Some(&json!(2)));
|
||||
assert_eq!(masked.pointer("/usage/total_tokens"), Some(&json!(3)));
|
||||
assert_eq!(masked.pointer("/usage/promptTokenCount"), Some(&json!(4)));
|
||||
assert_eq!(
|
||||
masked.pointer("/usage/candidatesTokenCount"),
|
||||
Some(&json!(5))
|
||||
);
|
||||
assert_eq!(
|
||||
masked.pointer("/generationConfig/maxOutputTokens"),
|
||||
Some(&json!(8192))
|
||||
);
|
||||
assert_eq!(
|
||||
masked.pointer("/generationConfig/maxOutputToken"),
|
||||
Some(&json!(4096))
|
||||
);
|
||||
assert_ne!(
|
||||
masked
|
||||
.pointer("/metadata/access_token")
|
||||
.and_then(Value::as_str),
|
||||
Some("secret-access-token-value")
|
||||
);
|
||||
assert_ne!(
|
||||
masked
|
||||
.pointer("/metadata/authToken")
|
||||
.and_then(Value::as_str),
|
||||
Some("secret-auth-token-value")
|
||||
);
|
||||
assert_ne!(
|
||||
masked.pointer("/metadata/token").and_then(Value::as_str),
|
||||
Some("secret-token-value")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sync_terminal_usage_redacts_provider_request_body_secrets_from_context() {
|
||||
let plan = ExecutionPlan {
|
||||
|
||||
Reference in New Issue
Block a user