Skip to content

Commit 94b5792

Browse files
committed
fix: widen token columns and add overflow-safe formatting
Input (8) and Output (9) columns were too narrow for large token counts. A value like 106529574 (9 digits) got its leading digit clipped in the 8-wide Input column, displaying as 06529574. - Unify all token columns (Cached, Input, Output, Reasoning) to width 12 via TOKEN_COL_WIDTH constant, in both daily and session views - Add format_number_fit() that cascades through progressively compact formats (user pref → human-readable → fewer decimals → plain digits) so significant digits are never silently clipped - Separator rows now use the constant for consistency - Fix clippy::collapsible_match in tui.rs, codex_cli.rs, copilot.rs - 10 new tests for format_number_fit
1 parent ac4af92 commit 94b5792

5 files changed

Lines changed: 436 additions & 189 deletions

File tree

src/analyzers/codex_cli.rs

Lines changed: 37 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -392,45 +392,43 @@ pub(crate) fn parse_codex_cli_jsonl_file(
392392
session_name: effective_name,
393393
});
394394
}
395-
"assistant" => {
396-
// Token usage is now emitted immediately when processing token_count
397-
// events. We still track assistant messages without additional stats
398-
// to avoid double-counting when Codex emits separate reasoning/tool
399-
// outputs.
400-
if !saw_token_usage {
401-
let model_state = session_model.clone().unwrap_or_else(|| {
402-
let fallback = SessionModel::inferred(
403-
DEFAULT_FALLBACK_MODEL.to_string(),
404-
);
405-
warn_once(format!(
406-
"WARNING: session {file_path_str} missing model metadata; using fallback model {} for cost estimation.",
407-
fallback.name
408-
));
409-
session_model = Some(fallback.clone());
410-
fallback
411-
});
412-
413-
entries.push(ConversationMessage {
414-
application: Application::CodexCli,
415-
model: Some(model_state.name.clone()),
416-
global_hash: hash_text(&format!(
417-
"{}_{}_assistant_{}",
418-
file_path_str,
419-
wrapper.timestamp.to_rfc3339(),
420-
entries.len()
421-
)),
422-
local_hash: None,
423-
conversation_hash: hash_text(&file_path_str),
424-
date: wrapper.timestamp,
425-
project_hash: "".to_string(),
426-
stats: Stats::default(),
427-
role: MessageRole::Assistant,
428-
uuid: None,
429-
session_name: session_name
430-
.clone()
431-
.or_else(|| fallback_session_name.clone()),
432-
});
433-
}
395+
// Token usage is now emitted immediately when processing token_count
396+
// events. We still track assistant messages without additional stats
397+
// to avoid double-counting when Codex emits separate reasoning/tool
398+
// outputs.
399+
"assistant" if !saw_token_usage => {
400+
let model_state = session_model.clone().unwrap_or_else(|| {
401+
let fallback = SessionModel::inferred(
402+
DEFAULT_FALLBACK_MODEL.to_string(),
403+
);
404+
warn_once(format!(
405+
"WARNING: session {file_path_str} missing model metadata; using fallback model {} for cost estimation.",
406+
fallback.name
407+
));
408+
session_model = Some(fallback.clone());
409+
fallback
410+
});
411+
412+
entries.push(ConversationMessage {
413+
application: Application::CodexCli,
414+
model: Some(model_state.name.clone()),
415+
global_hash: hash_text(&format!(
416+
"{}_{}_assistant_{}",
417+
file_path_str,
418+
wrapper.timestamp.to_rfc3339(),
419+
entries.len()
420+
)),
421+
local_hash: None,
422+
conversation_hash: hash_text(&file_path_str),
423+
date: wrapper.timestamp,
424+
project_hash: "".to_string(),
425+
stats: Stats::default(),
426+
role: MessageRole::Assistant,
427+
uuid: None,
428+
session_name: session_name
429+
.clone()
430+
.or_else(|| fallback_session_name.clone()),
431+
});
434432
}
435433
_ => {}
436434
}

src/analyzers/copilot.rs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -149,15 +149,14 @@ fn count_tokens(text: &str) -> u64 {
149149
// Recursively extract all text content from a nested JSON structure
150150
fn extract_text_from_value(value: &simd_json::OwnedValue, accumulated_text: &mut String) {
151151
match value {
152-
simd_json::OwnedValue::String(s) => {
153-
// Only accumulate if it's a "text" field value, not metadata like URIs
152+
// Only accumulate if it's a "text" field value, not metadata like URIs
153+
simd_json::OwnedValue::String(s)
154154
if !s.starts_with("vscode-")
155155
&& !s.starts_with("file://")
156-
&& !s.starts_with("ssh-remote")
157-
{
158-
accumulated_text.push_str(s);
159-
accumulated_text.push(' ');
160-
}
156+
&& !s.starts_with("ssh-remote") =>
157+
{
158+
accumulated_text.push_str(s);
159+
accumulated_text.push(' ');
161160
}
162161
simd_json::OwnedValue::Object(obj) => {
163162
// Look for "text" fields specifically

0 commit comments

Comments
 (0)