Capture rollout budget units from response usage (#36641)

## What changed

- Parse `codex_rollout_budget_units` from completed Responses API usage into
  `TokenUsage`.
- Keep the provider-only value out of serialized protocol, JSON schema, and
  TypeScript representations.

## Testing

- Cover the value in unit and end-to-end SSE response parsing tests.

GitOrigin-RevId: a53d4202beb9c8985d25894cb10e7c01f20b2a44
This commit is contained in:
rka-oai
2026-08-03 00:30:57 +00:00
committed by copyberry
parent 5157493c23
commit bb5054fe47
18 changed files with 63 additions and 3 deletions
+6 -1
View File
@@ -126,6 +126,8 @@ struct ResponseCompletedUsage {
output_tokens: i64,
output_tokens_details: Option<ResponseCompletedOutputTokensDetails>,
total_tokens: i64,
#[serde(default)]
codex_rollout_budget_units: Option<serde_json::Number>,
}
impl From<ResponseCompletedUsage> for TokenUsage {
@@ -141,6 +143,7 @@ impl From<ResponseCompletedUsage> for TokenUsage {
.map(|d| d.reasoning_tokens)
.unwrap_or(0),
total_tokens: val.total_tokens,
codex_rollout_budget_units: val.codex_rollout_budget_units,
}
}
}
@@ -816,7 +819,8 @@ mod tests {
},
"output_tokens": 10,
"output_tokens_details": { "reasoning_tokens": 5 },
"total_tokens": 110
"total_tokens": 110,
"codex_rollout_budget_units": 2.5
}))
.expect("valid response usage");
@@ -829,6 +833,7 @@ mod tests {
output_tokens: 10,
reasoning_output_tokens: 5,
total_tokens: 110,
codex_rollout_budget_units: serde_json::Number::from_f64(2.5),
}
);
}
+20 -2
View File
@@ -111,7 +111,15 @@ async fn responses_stream_parses_items_and_completed_end_to_end() -> Result<()>
let completed = serde_json::json!({
"type": "response.completed",
"response": { "id": "resp1" }
"response": {
"id": "resp1",
"usage": {
"input_tokens": 10,
"output_tokens": 5,
"total_tokens": 15,
"codex_rollout_budget_units": 2.5
}
}
});
let body = build_responses_body(vec![item1, item2, completed]);
@@ -160,7 +168,17 @@ async fn responses_stream_parses_items_and_completed_end_to_end() -> Result<()>
end_turn,
} => {
assert_eq!(response_id, "resp1");
assert!(token_usage.is_none());
assert_eq!(
token_usage.as_ref().map(|usage| usage.total_tokens),
Some(15)
);
assert_eq!(
token_usage
.as_ref()
.and_then(|usage| usage.codex_rollout_budget_units.as_ref())
.and_then(serde_json::Number::as_f64),
Some(2.5)
);
assert!(end_turn.is_none());
}
other => panic!("unexpected third event: {other:?}"),