mirror of
https://github.com/openai/codex.git
synced 2026-11-13 14:46:14 +00:00
Show estimated thread usage in /status (#38281)
## What changed - Extend `account/usage/read` with an optional `threadId` request and a backward-compatible `threadUsage` response containing estimated credits, optional USD cost, and model, reasoning, speed, and token breakdowns. - Fetch thread usage for eligible Business and Enterprise plans when `/status` is opened, then update the rendered status card asynchronously. - Preserve terminal scrollback when replacing a visible status-card tail, and append a refreshed card when the original tail can no longer be updated. ## Testing - Add app-server coverage for authentication, canonical thread IDs, unavailable billing routes, and malformed IDs. - Add TUI coverage for usage formatting, stale responses, retries, history updates, terminal reflow, and scrollback preservation. GitOrigin-RevId: 49300914b3fba917c0f08e8595363e04e5ba6d37
This commit is contained in:
1 parent
27a98dde4d
commit
f1a1fce26a
55 files changed
+2903
-60
No files matched your search
@@ -2145,6 +2145,17 @@ mod tests {
|
||||
client_request_ts.contains("MockExperimentalMethodParams"),
|
||||
false
|
||||
);
|
||||
const LEGACY_ACCOUNT_USAGE_REQUEST: &str = concat!(
|
||||
"{ \"method\": \"account/usage/read\", id: RequestId, ",
|
||||
"params?: GetAccountTokenUsageParams | undefined, }"
|
||||
);
|
||||
assert!(client_request_ts.contains(LEGACY_ACCOUNT_USAGE_REQUEST));
|
||||
let account_usage_response_ts = std::str::from_utf8(
|
||||
fixture_tree
|
||||
.get(Path::new("v2/GetAccountTokenUsageResponse.ts"))
|
||||
.ok_or_else(|| anyhow::anyhow!("missing account usage response fixture"))?,
|
||||
)?;
|
||||
assert!(account_usage_response_ts.contains("threadUsage?: ThreadUsage | null"));
|
||||
let server_request_ts = std::str::from_utf8(
|
||||
fixture_tree
|
||||
.get(Path::new("ServerRequest.ts"))
|
||||
@@ -2217,7 +2228,12 @@ mod tests {
|
||||
});
|
||||
|
||||
let contents = std::str::from_utf8(contents)?;
|
||||
if contents.contains("| undefined") {
|
||||
// The stable usage RPC originally required `params: undefined`. Keep that exact
|
||||
// legacy value accepted while extending the same method with optional thread params.
|
||||
let legacy_account_usage_undefined = path == Path::new("ClientRequest.ts")
|
||||
&& contents.matches("| undefined").count() == 1
|
||||
&& contents.contains(LEGACY_ACCOUNT_USAGE_REQUEST);
|
||||
if contents.contains("| undefined") && !legacy_account_usage_undefined {
|
||||
undefined_offenders.push(path.clone());
|
||||
}
|
||||
|
||||
@@ -2329,9 +2345,14 @@ mod tests {
|
||||
|
||||
// If the last non-whitespace before ':' is '?', then this is an
|
||||
// optional field with a nullable type (i.e., "?: T | null").
|
||||
// These are only allowed in *Params types.
|
||||
// These are only allowed in *Params types, except the additive stable usage
|
||||
// response field, which older servers omit and newer servers return as null.
|
||||
let legacy_account_usage_response = path
|
||||
== Path::new("v2/GetAccountTokenUsageResponse.ts")
|
||||
&& field_prefix.trim() == "threadUsage?";
|
||||
if field_prefix.chars().rev().find(|c| !c.is_whitespace()) == Some('?')
|
||||
&& !allow_optional_nullable
|
||||
&& !legacy_account_usage_response
|
||||
{
|
||||
let line_number =
|
||||
contents[..abs_idx].chars().filter(|c| *c == '\n').count() + 1;
|
||||
|
||||
Reference in new issue
Block a user