mirror of
https://github.com/fawney19/Aether.git
synced 2026-10-10 03:09:50 +08:00
fix(claude-code): 额度查询携带 x-app/claude-cli UA 以获取 cedar_ember,并在无重置机会时显式清空
This commit is contained in:
@@ -456,12 +456,15 @@ pub fn parse_claude_code_oauth_usage_response(
|
|||||||
bucket.insert(format!("{prefix}_reset_at"), serde_json::json!(reset_at));
|
bucket.insert(format!("{prefix}_reset_at"), serde_json::json!(reset_at));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(reset_credits) = parse_claude_code_reset_credits(root, updated_at_unix_secs) {
|
|
||||||
bucket.insert("reset_credits".to_string(), reset_credits);
|
|
||||||
}
|
|
||||||
if bucket.is_empty() {
|
if bucket.is_empty() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
// Explicit null so a refresh overwrites (rather than keeps) credits that were used up.
|
||||||
|
bucket.insert(
|
||||||
|
"reset_credits".to_string(),
|
||||||
|
parse_claude_code_reset_credits(root, updated_at_unix_secs)
|
||||||
|
.unwrap_or(serde_json::Value::Null),
|
||||||
|
);
|
||||||
bucket.insert(
|
bucket.insert(
|
||||||
"updated_at".to_string(),
|
"updated_at".to_string(),
|
||||||
serde_json::json!(updated_at_unix_secs),
|
serde_json::json!(updated_at_unix_secs),
|
||||||
@@ -7934,6 +7937,45 @@ mod claude_code_quota_tests {
|
|||||||
assert!(!credits.to_string().contains("launch"));
|
assert!(!credits.to_string().contains("launch"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn real_cedar_ember_response_survives_metadata_redaction() {
|
||||||
|
// Shape captured from a live Claude Pro account (unrelated fields trimmed).
|
||||||
|
let parsed = parse_claude_code_oauth_usage_response(
|
||||||
|
&json!({
|
||||||
|
"five_hour": {"utilization": 32.0, "resets_at": "2026-09-29T19:19:59.933008+00:00"},
|
||||||
|
"cedar_ember": {
|
||||||
|
"eligible": true,
|
||||||
|
"at_limit": false,
|
||||||
|
"grants": [{
|
||||||
|
"id": "opus55-launch-promax-20260921",
|
||||||
|
"label": "Claude Opus 5.5 launch",
|
||||||
|
"resets_total": 1,
|
||||||
|
"resets_left": 1,
|
||||||
|
"starts_at": "2026-09-22T16:00:00+00:00",
|
||||||
|
"ends_at": "2026-10-22T16:00:00+00:00",
|
||||||
|
"clears": ["five_hour", "seven_day"],
|
||||||
|
"paused": false,
|
||||||
|
"usable_now": true,
|
||||||
|
"use_requires_limit": false
|
||||||
|
}],
|
||||||
|
"next_grant_id": "opus55-launch-promax-20260921"
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
1_790_699_000,
|
||||||
|
)
|
||||||
|
.expect("usage should parse");
|
||||||
|
assert_eq!(parsed["reset_credits"]["available_count"], json!(1));
|
||||||
|
|
||||||
|
let safe = crate::provider::redaction::admin_provider_upstream_metadata_safe_json(Some(
|
||||||
|
&json!({ "claude_code": parsed }),
|
||||||
|
));
|
||||||
|
assert_eq!(
|
||||||
|
safe["claude_code"]["reset_credits"]["available_count"],
|
||||||
|
json!(1),
|
||||||
|
"redaction dropped reset_credits: {safe}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn cedar_ember_null_or_empty_omits_reset_credits() {
|
fn cedar_ember_null_or_empty_omits_reset_credits() {
|
||||||
let parsed = parse_claude_code_oauth_usage_response(
|
let parsed = parse_claude_code_oauth_usage_response(
|
||||||
@@ -7941,7 +7983,7 @@ mod claude_code_quota_tests {
|
|||||||
1,
|
1,
|
||||||
)
|
)
|
||||||
.expect("usage should parse");
|
.expect("usage should parse");
|
||||||
assert!(parsed.get("reset_credits").is_none());
|
assert!(parsed["reset_credits"].is_null());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ use crate::quota_refresh::ProviderPoolQuotaRequestSpec;
|
|||||||
pub const CLAUDE_CODE_OAUTH_USAGE_URL: &str =
|
pub const CLAUDE_CODE_OAUTH_USAGE_URL: &str =
|
||||||
"https://api.anthropic.com/api/oauth/usage?cedar_ember=1&skip_spend=1";
|
"https://api.anthropic.com/api/oauth/usage?cedar_ember=1&skip_spend=1";
|
||||||
pub const CLAUDE_CODE_OAUTH_BETA: &str = "oauth-2025-04-20";
|
pub const CLAUDE_CODE_OAUTH_BETA: &str = "oauth-2025-04-20";
|
||||||
pub const CLAUDE_CODE_USAGE_USER_AGENT: &str = "claude-code/2.1.284";
|
pub const CLAUDE_CODE_USAGE_USER_AGENT: &str = "claude-cli/2.1.284 (external, cli)";
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default)]
|
#[derive(Debug, Clone, Default)]
|
||||||
pub struct ClaudeCodeProviderPoolAdapter;
|
pub struct ClaudeCodeProviderPoolAdapter;
|
||||||
@@ -58,6 +58,8 @@ pub fn build_claude_code_pool_quota_request(
|
|||||||
"anthropic-beta".to_string(),
|
"anthropic-beta".to_string(),
|
||||||
CLAUDE_CODE_OAUTH_BETA.to_string(),
|
CLAUDE_CODE_OAUTH_BETA.to_string(),
|
||||||
),
|
),
|
||||||
|
// The reset-credit (`cedar_ember`) block is only returned to first-party CLI callers.
|
||||||
|
("x-app".to_string(), "cli".to_string()),
|
||||||
(
|
(
|
||||||
"user-agent".to_string(),
|
"user-agent".to_string(),
|
||||||
CLAUDE_CODE_USAGE_USER_AGENT.to_string(),
|
CLAUDE_CODE_USAGE_USER_AGENT.to_string(),
|
||||||
|
|||||||
Reference in New Issue
Block a user