Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion codex-rs/exec/src/event_processor_with_human_output.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ use codex_core::protocol::TaskCompleteEvent;
use codex_core::protocol::TurnAbortReason;
use codex_core::protocol::TurnDiffEvent;
use codex_core::protocol::WebSearchBeginEvent;
use codex_core::protocol::format_token_count;
use owo_colors::OwoColorize;
use owo_colors::Style;
use shlex::try_join;
Expand Down Expand Up @@ -189,7 +190,8 @@ impl EventProcessor for EventProcessorWithHumanOutput {
return CodexStatus::InitiateShutdown;
}
EventMsg::TokenCount(token_usage) => {
ts_println!(self, "tokens used: {}", token_usage.blended_total());
let tokens = format_token_count(token_usage.blended_total());
ts_println!(self, "tokens used: {tokens}");
}
EventMsg::AgentMessageDelta(AgentMessageDeltaEvent { delta }) => {
if !self.answer_started {
Expand Down
42 changes: 29 additions & 13 deletions codex-rs/protocol/src/protocol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -558,6 +558,17 @@ impl TokenUsage {
}
}

/// Format a token count with thousands separators for readability.
pub fn format_token_count(value: u64) -> String {
let mut s = value.to_string();
let mut i = s.len();
while i > 3 {
i -= 3;
s.insert(i, ',');
}
s
}

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct FinalOutput {
pub token_usage: TokenUsage,
Expand All @@ -572,21 +583,26 @@ impl From<TokenUsage> for FinalOutput {
impl fmt::Display for FinalOutput {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let token_usage = &self.token_usage;
let total = format_token_count(token_usage.blended_total());
let input = format_token_count(token_usage.non_cached_input());
let cached = token_usage.cached_input();
let cached_str = if cached > 0 {
let cached_tokens = format_token_count(cached);
format!(" (+ {cached_tokens} cached)")
} else {
String::new()
};
let output = format_token_count(token_usage.output_tokens);
let reasoning = token_usage
.reasoning_output_tokens
.map(|r| {
let reasoning_tokens = format_token_count(r);
format!(" (reasoning {reasoning_tokens})")
})
.unwrap_or_default();
write!(
f,
"Token usage: total={} input={}{} output={}{}",
token_usage.blended_total(),
token_usage.non_cached_input(),
if token_usage.cached_input() > 0 {
format!(" (+ {} cached)", token_usage.cached_input())
} else {
String::new()
},
token_usage.output_tokens,
token_usage
.reasoning_output_tokens
.map(|r| format!(" (reasoning {r})"))
.unwrap_or_default()
"Token usage: total={total} input={input}{cached_str} output={output}{reasoning}"
)
}
}
Expand Down
4 changes: 3 additions & 1 deletion codex-rs/tui/src/bottom_pane/chat_composer.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use codex_core::protocol::TokenUsage;
use codex_core::protocol::format_token_count;
use crossterm::event::KeyCode;
use crossterm::event::KeyEvent;
use crossterm::event::KeyModifiers;
Expand Down Expand Up @@ -1153,8 +1154,9 @@ impl WidgetRef for &ChatComposer {
if let Some(token_usage_info) = &self.token_usage_info {
let token_usage = &token_usage_info.total_token_usage;
hint.push(Span::from(" "));
let tokens = format_token_count(token_usage.blended_total());
hint.push(
Span::from(format!("{} tokens used", token_usage.blended_total()))
Span::from(format!("{tokens} tokens used"))
.style(Style::default().add_modifier(Modifier::DIM)),
);
let last_token_usage = &token_usage_info.last_token_usage;
Expand Down
10 changes: 6 additions & 4 deletions codex-rs/tui/src/history_cell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use codex_core::protocol::McpInvocation;
use codex_core::protocol::SandboxPolicy;
use codex_core::protocol::SessionConfiguredEvent;
use codex_core::protocol::TokenUsage;
use codex_core::protocol::format_token_count;
use codex_login::get_auth_file;
use codex_login::try_read_auth_json;
use codex_protocol::parse_command::ParsedCommand;
Expand Down Expand Up @@ -734,23 +735,24 @@ pub(crate) fn new_status_output(
// Input: <input> [+ <cached> cached]
let mut input_line_spans: Vec<Span<'static>> = vec![
" • Input: ".into(),
usage.non_cached_input().to_string().into(),
format_token_count(usage.non_cached_input()).into(),
];
if let Some(cached) = usage.cached_input_tokens
&& cached > 0
{
input_line_spans.push(format!(" (+ {cached} cached)").into());
let cached_tokens = format_token_count(cached);
input_line_spans.push(format!(" (+ {cached_tokens} cached)").into());
}
lines.push(Line::from(input_line_spans));
// Output: <output>
lines.push(Line::from(vec![
" • Output: ".into(),
usage.output_tokens.to_string().into(),
format_token_count(usage.output_tokens).into(),
]));
// Total: <total>
lines.push(Line::from(vec![
" • Total: ".into(),
usage.blended_total().to_string().into(),
format_token_count(usage.blended_total()).into(),
]));

PlainHistoryCell { lines }
Expand Down
Loading