use super::utils::{
estimate_tokens, file_modified_timestamp_ms, for_each_json_line, session_id_from_path,
workspace_key_from_path,
};
use super::{workspace_label_from_key, UnifiedMessage};
use crate::TokenBreakdown;
use serde::Deserialize;
use std::path::Path;
const CLIENT_ID: &str = "commandcode";
const PROVIDER_ID: &str = "command-code";
const UNKNOWN_MODEL: &str = "unknown";
#[derive(Debug, Deserialize)]
struct CommandCodeEntry {
#[serde(rename = "type")]
record_type: Option<String>,
id: Option<String>,
#[serde(rename = "parentId")]
parent_id: Option<String>,
timestamp: Option<String>,
message: Option<CommandCodeMessage>,
usage: Option<CommandCodeUsage>,
model: Option<String>,
role: Option<String>,
content: Option<serde_json::Value>,
#[serde(rename = "sessionId")]
session_id: Option<String>,
}
#[derive(Debug, Deserialize)]
struct CommandCodeMessage {
role: Option<String>,
content: Option<serde_json::Value>,
}
#[derive(Debug, Deserialize)]
struct CommandCodeUsage {
#[serde(rename = "inputTokens")]
input_tokens: Option<i64>,
#[serde(rename = "outputTokens")]
output_tokens: Option<i64>,
#[serde(rename = "cacheReadTokens")]
cache_read_tokens: Option<i64>,
#[serde(rename = "cacheWriteTokens")]
cache_write_tokens: Option<i64>,
#[serde(rename = "costUsd")]
cost_usd: Option<f64>,
}
impl CommandCodeUsage {
fn to_breakdown(&self) -> Option<TokenBreakdown> {
let any_bucket_reported = self.input_tokens.is_some()
|| self.output_tokens.is_some()
|| self.cache_read_tokens.is_some()
|| self.cache_write_tokens.is_some();
if !any_bucket_reported {
return None;
}
const TOKEN_CEILING: i64 = 1_000_000_000_000;
let input = self.input_tokens.unwrap_or(0).clamp(0, TOKEN_CEILING);
let output = self.output_tokens.unwrap_or(0).clamp(0, TOKEN_CEILING);
let cache_read = self.cache_read_tokens.unwrap_or(0).clamp(0, TOKEN_CEILING);
let cache_write = self.cache_write_tokens.unwrap_or(0).clamp(0, TOKEN_CEILING);
Some(TokenBreakdown {
input,
output,
cache_read,
cache_write,
reasoning: 0,
})
}
fn reported_cost(&self) -> Option<f64> {
const COST_CEILING: f64 = 1_000_000.0;
self.cost_usd
.filter(|cost| cost.is_finite() && *cost >= 0.0 && *cost <= COST_CEILING)
}
}
#[derive(Debug, Deserialize)]
struct CommandCodeConfig {
model: Option<String>,
}
pub fn parse_commandcode_file(path: &Path) -> Vec<UnifiedMessage> {
if path
.file_name()
.and_then(|name| name.to_str())
.is_some_and(|name| name.ends_with(".checkpoints.jsonl"))
{
return Vec::new();
}
let fallback_timestamp = file_modified_timestamp_ms(path);
let session_id_from_path = session_id_from_path(path);
let workspace_key = workspace_key_from_path(path);
let workspace_label = workspace_key.as_deref().and_then(workspace_label_from_key);
let config_model = model_from_config(path);
let mut messages = Vec::new();
let mut session_id: Option<String> = None;
let mut model_id: Option<String> = None;
let mut turn_input_chars: usize = 0;
let mut pending_turn_start = false;
let mut assistant_index = 0usize;
let mut message_entry_ids: Vec<Option<String>> = Vec::new();
let mut parent_map: std::collections::HashMap<String, Option<String>> =
std::collections::HashMap::new();
let mut last_entry_id: Option<String> = None;
for_each_json_line(path, &mut |_index, trimmed| {
let entry = match serde_json::from_str::<CommandCodeEntry>(trimmed) {
Ok(entry) => entry,
Err(_) => return,
};
if entry.record_type.as_deref() == Some("session") {
if let Some(id) = entry.id.as_deref().filter(|id| !id.is_empty()) {
session_id = Some(id.to_string());
}
} else if session_id.is_none() {
if let Some(id) = entry.session_id.as_deref().filter(|id| !id.is_empty()) {
session_id = Some(id.to_string());
}
}
if let Some(model) = entry.model.as_deref().filter(|model| !model.is_empty()) {
model_id = Some(model.to_string());
}
if let Some(id) = entry.id.as_deref().filter(|id| !id.is_empty()) {
let parent = entry
.parent_id
.as_deref()
.filter(|parent| !parent.is_empty())
.map(str::to_string);
parent_map.insert(id.to_string(), parent);
last_entry_id = Some(id.to_string());
}
match entry.record_type.as_deref() {
Some("model_change") => {}
_ => {
let message = match entry.message.as_ref() {
Some(message) => message,
None if entry.role.is_some() || entry.content.is_some() => {
&legacy_message(&entry)
}
None => return,
};
let Some(role) = message.role.as_deref() else {
return;
};
let chars = message.content.as_ref().map(content_chars).unwrap_or(0);
if role == "assistant" {
let breakdown = entry
.usage
.as_ref()
.and_then(CommandCodeUsage::to_breakdown)
.unwrap_or_else(|| {
let input = estimate_tokens(turn_input_chars);
let output = estimate_tokens(chars);
TokenBreakdown {
input,
output,
cache_read: 0,
cache_write: 0,
reasoning: 0,
}
});
turn_input_chars = 0;
let cost = entry.usage.as_ref().and_then(|u| u.reported_cost());
if breakdown.total() == 0 && !cost.is_some_and(|usd| usd > 0.0) {
return;
}
let resolved_session = session_id
.clone()
.unwrap_or_else(|| session_id_from_path.clone());
let raw_model = match model_id {
Some(ref model) => model.clone(),
None => config_model
.clone()
.unwrap_or_else(|| UNKNOWN_MODEL.to_string()),
};
let resolved_model = canonicalize_model(&raw_model);
let provider_id = provider_hint_for_model(&raw_model).unwrap_or(PROVIDER_ID);
let timestamp = entry
.timestamp
.as_deref()
.and_then(parse_rfc3339_ms)
.unwrap_or(fallback_timestamp);
let dedup_timestamp = entry
.timestamp
.as_deref()
.and_then(parse_rfc3339_ms)
.unwrap_or(-1);
let dedup_key = entry
.id
.as_deref()
.map(|id| format!("{}:{}", id, dedup_timestamp));
let mut message = UnifiedMessage::new_with_dedup(
CLIENT_ID,
resolved_model,
provider_id,
resolved_session.clone(),
timestamp,
breakdown,
cost.unwrap_or(0.0),
dedup_key.or_else(|| {
Some(format!(
"{}:{}:{}",
workspace_key.as_deref().unwrap_or("-"),
resolved_session,
assistant_index
))
}),
);
message.message_count = 1;
message.is_turn_start = pending_turn_start;
message.set_workspace(workspace_key.clone(), workspace_label.clone());
if cost.is_some() {
message.mark_provider_reported_cost();
}
message_entry_ids.push(entry.id.clone());
messages.push(message);
assistant_index += 1;
pending_turn_start = false;
} else if role == "user" {
if !is_tool_result(&message.content) {
pending_turn_start = true;
}
turn_input_chars += chars;
} else {
turn_input_chars += chars;
}
}
}
});
if let Some(branch) = active_branch_ids(&parent_map, last_entry_id.as_deref()) {
let mut kept = Vec::with_capacity(messages.len());
for (message, entry_id) in messages.into_iter().zip(message_entry_ids) {
if entry_id.as_deref().is_none_or(|id| branch.contains(id)) {
kept.push(message);
}
}
kept
} else {
messages
}
}
fn active_branch_ids(
parent_map: &std::collections::HashMap<String, Option<String>>,
last_entry_id: Option<&str>,
) -> Option<std::collections::HashSet<String>> {
let mut branch = std::collections::HashSet::new();
let mut current = last_entry_id.map(str::to_string)?;
loop {
if !branch.insert(current.clone()) {
return Some(branch);
}
match parent_map.get(¤t) {
Some(Some(parent)) => current = parent.clone(),
Some(None) => return Some(branch),
None => return None,
}
}
}
fn legacy_message(entry: &CommandCodeEntry) -> CommandCodeMessage {
CommandCodeMessage {
role: entry.role.clone(),
content: entry.content.clone(),
}
}
fn is_tool_result(content: &Option<serde_json::Value>) -> bool {
match content {
Some(serde_json::Value::Array(items)) => items
.iter()
.filter_map(serde_json::Value::as_object)
.any(|block| {
block.get("type").and_then(serde_json::Value::as_str) == Some("tool_result")
}),
Some(serde_json::Value::Object(map)) => {
map.get("type").and_then(serde_json::Value::as_str) == Some("tool_result")
}
_ => false,
}
}
fn content_chars(content: &serde_json::Value) -> usize {
match content {
serde_json::Value::Null => 0,
serde_json::Value::String(s) if s.is_empty() => 0,
serde_json::Value::Array(items) if items.is_empty() => 0,
serde_json::Value::Object(map) if map.is_empty() => 0,
_ => serde_json::to_string(content)
.map(|serialized| serialized.chars().count())
.unwrap_or(0),
}
}
fn canonicalize_model(model: &str) -> String {
model.rsplit('/').next().unwrap_or(model).to_string()
}
fn provider_hint_for_model(model: &str) -> Option<&'static str> {
crate::provider_identity::inferred_provider_from_model(model)
}
fn parse_rfc3339_ms(timestamp: &str) -> Option<i64> {
chrono::DateTime::parse_from_rfc3339(timestamp)
.ok()
.map(|dt| dt.timestamp_millis())
}
fn model_from_config(session_path: &Path) -> Option<String> {
let mut dir = session_path.parent()?;
loop {
if dir.file_name().and_then(|name| name.to_str()) == Some("projects") {
break;
}
dir = dir.parent()?;
}
let commandcode_root = dir.parent()?;
let config_path = commandcode_root.join("config.json");
let bytes = std::fs::read(config_path).ok()?;
let config: CommandCodeConfig = serde_json::from_slice(&bytes).ok()?;
config.model.filter(|model| !model.trim().is_empty())
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
use std::io::Write;
use tempfile::TempDir;
fn write_session(dir: &TempDir, slug: &str, session: &str, jsonl: &str) -> std::path::PathBuf {
let project_dir = dir.path().join("projects").join(slug);
std::fs::create_dir_all(&project_dir).unwrap();
let path = project_dir.join(format!("{session}.jsonl"));
let mut file = std::fs::File::create(&path).unwrap();
file.write_all(jsonl.as_bytes()).unwrap();
path
}
fn write_config(dir: &TempDir, model: &str) {
let path = dir.path().join("config.json");
let mut file = std::fs::File::create(&path).unwrap();
write!(file, r#"{{"provider":"command-code","model":"{model}"}}"#).unwrap();
}
#[allow(clippy::too_many_arguments)]
fn assistant_line(
id: &str,
parent: &str,
timestamp: &str,
model: &str,
text: &str,
input: i64,
output: i64,
cache_read: i64,
cost_usd: f64,
) -> String {
json!({
"type": "message",
"id": id,
"parentId": parent,
"timestamp": timestamp,
"message": {
"role": "assistant",
"content": [{"type": "text", "text": text}]
},
"usage": {
"inputTokens": input,
"outputTokens": output,
"cacheReadTokens": cache_read,
"cacheWriteTokens": 0,
"costUsd": cost_usd
},
"model": model
})
.to_string()
}
fn user_line(id: &str, parent: &str, timestamp: &str, text: &str) -> String {
json!({
"type": "message",
"id": id,
"parentId": parent,
"timestamp": timestamp,
"message": {
"role": "user",
"content": [{"type": "text", "text": text}]
}
})
.to_string()
}
fn tool_result_line(
id: &str,
parent: &str,
timestamp: &str,
tool_use_id: &str,
text: &str,
) -> String {
json!({
"type": "message",
"id": id,
"parentId": parent,
"timestamp": timestamp,
"message": {
"role": "user",
"content": [{
"type": "tool_result",
"tool_use_id": tool_use_id,
"content": [{"type": "text", "text": text}]
}]
}
})
.to_string()
}
#[test]
fn test_parse_realistic_v3_session_with_tool_turns() {
let dir = TempDir::new().unwrap();
write_config(&dir, "deepseek/deepseek-v4-flash");
let jsonl = format!(
"{}\n{}\n{}\n{}\n{}\n{}",
json!({"type": "session", "version": 3, "id": "sess-1", "timestamp": "2026-08-31T04:36:38.441Z", "cwd": "/home/al/learning"}),
json!({"type": "model_change", "id": "m1", "parentId": null, "timestamp": "2026-08-31T04:37:00.000Z", "model": "deepseek/deepseek-v4-flash"}),
user_line("u1", "m1", "2026-08-31T04:39:16.867Z", "list the repo"),
json!({
"type": "message",
"id": "t1",
"parentId": "u1",
"timestamp": "2026-08-31T04:39:18.000Z",
"message": {
"role": "assistant",
"content": [{
"type": "tool_use",
"id": "call_00_abc",
"name": "read_directory",
"input": {"path": "/home/al/learning"}
}],
"meta": {"source": "model"}
},
"usage": {
"inputTokens": 21000,
"outputTokens": 90,
"cacheReadTokens": 4000,
"cacheWriteTokens": 0,
"costUsd": 0.002
},
"model": "deepseek/deepseek-v4-flash"
}),
tool_result_line(
"r1",
"t1",
"2026-08-31T04:39:19.000Z",
"call_00_abc",
"Found 28 items"
),
assistant_line(
"a1",
"r1",
"2026-08-31T04:39:20.351Z",
"deepseek/deepseek-v4-flash",
"There are 28 items.",
28534,
205,
7424,
0.006464748
),
);
let path = write_session(&dir, "home-al-learning", "sess-1", &jsonl);
let messages = parse_commandcode_file(&path);
assert_eq!(messages.len(), 2);
let tool_call = &messages[0];
assert_eq!(tool_call.model_id, "deepseek-v4-flash");
assert_eq!(tool_call.provider_id, "deepseek");
assert_eq!(tool_call.tokens.input, 21000);
assert_eq!(tool_call.tokens.output, 90);
assert_eq!(tool_call.tokens.cache_read, 4000);
assert!((tool_call.cost - 0.002).abs() < 1e-9);
assert!(tool_call.has_authoritative_cost());
assert!(tool_call.is_turn_start);
assert_eq!(tool_call.dedup_key.as_deref(), Some("t1:1788151158000"));
let msg = &messages[1];
assert_eq!(msg.model_id, "deepseek-v4-flash");
assert_eq!(msg.provider_id, "deepseek");
assert_eq!(msg.session_id, "sess-1");
assert_eq!(msg.tokens.input, 28534);
assert_eq!(msg.tokens.output, 205);
assert_eq!(msg.tokens.cache_read, 7424);
assert!((msg.cost - 0.006464748).abs() < 1e-9);
assert!(msg.has_authoritative_cost());
assert!(!msg.is_turn_start);
assert_eq!(msg.dedup_key.as_deref(), Some("a1:1788151160351"));
}
#[test]
fn test_abandoned_rewind_branch_entries_are_dropped() {
let dir = TempDir::new().unwrap();
write_config(&dir, "model-x");
let jsonl = format!(
"{}\n{}\n{}\n{}\n{}",
json!({"type": "session", "version": 3, "id": "s"}),
user_line("u1", "", "2026-08-31T00:00:00Z", "original prompt"),
assistant_line(
"a1",
"u1",
"2026-08-31T00:00:05Z",
"model-x",
"first answer (abandoned by /rewind)",
5000,
200,
1000,
0.01
),
user_line("u2", "u1", "2026-08-31T00:00:10Z", "actually, redo it"),
assistant_line(
"a2",
"u2",
"2026-08-31T00:00:15Z",
"model-x",
"the real final answer",
6000,
300,
2000,
0.02
),
);
let path = write_session(&dir, "proj", "s", &jsonl);
let messages = parse_commandcode_file(&path);
assert_eq!(messages.len(), 1, "orphaned branch entries must be dropped");
let msg = &messages[0];
assert_eq!(msg.model_id, "model-x");
assert_eq!(msg.tokens.input, 6000);
assert_eq!(msg.tokens.output, 300);
assert_eq!(msg.tokens.cache_read, 2000);
assert!((msg.cost - 0.02).abs() < 1e-9);
assert!(msg.is_turn_start);
}
#[test]
fn test_unparseable_midfile_line_does_not_discard_earlier_turns() {
let dir = TempDir::new().unwrap();
write_config(&dir, "model-x");
let jsonl = format!(
"{}\n{}\n{}\n{}\n{}",
json!({"type": "session", "version": 3, "id": "s"}),
user_line("u1", "", "2026-08-31T00:00:00Z", "first prompt"),
assistant_line(
"a1",
"u1",
"2026-08-31T00:00:05Z",
"model-x",
"first answer",
1000,
100,
0,
0.01
),
r#"{"type":"message","id":"u2","parentId":"a1","timestamp":"2026-08-3"#,
assistant_line(
"a2",
"u2",
"2026-08-31T00:00:15Z",
"model-x",
"second answer",
2000,
200,
0,
0.02
),
);
let path = write_session(&dir, "proj", "s", &jsonl);
let messages = parse_commandcode_file(&path);
assert_eq!(
messages.len(),
2,
"the turn before the damaged line must survive it"
);
assert_eq!(
messages.iter().map(|m| m.tokens.input).sum::<i64>(),
3000,
"both turns' authoritative input tokens must be kept"
);
assert!(
(messages.iter().map(|m| m.cost).sum::<f64>() - 0.03).abs() < 1e-9,
"both turns' authoritative cost must be kept"
);
}
#[test]
fn test_null_root_chain_still_drops_abandoned_branch() {
let dir = TempDir::new().unwrap();
write_config(&dir, "model-x");
let jsonl = format!(
"{}\n{}\n{}\n{}\n{}",
json!({"type": "session", "version": 3, "id": "s"}),
json!({
"type": "message",
"id": "u1",
"parentId": null,
"timestamp": "2026-08-31T00:00:00Z",
"message": {"role": "user", "content": [{"type": "text", "text": "original"}]}
}),
assistant_line(
"a1",
"u1",
"2026-08-31T00:00:05Z",
"model-x",
"abandoned by /rewind",
5000,
200,
1000,
0.01
),
user_line("u2", "u1", "2026-08-31T00:00:10Z", "actually, redo it"),
assistant_line(
"a2",
"u2",
"2026-08-31T00:00:15Z",
"model-x",
"the real final answer",
6000,
300,
2000,
0.02
),
);
let path = write_session(&dir, "proj", "s", &jsonl);
let messages = parse_commandcode_file(&path);
assert_eq!(
messages.len(),
1,
"a complete chain to a null root must still drop the abandoned branch"
);
assert_eq!(messages[0].tokens.input, 6000);
assert!((messages[0].cost - 0.02).abs() < 1e-9);
}
#[test]
fn test_fork_copies_share_dedup_key() {
let dir = TempDir::new().unwrap();
write_config(&dir, "model-x");
let original = format!(
"{}\n{}\n{}",
json!({"type": "session", "version": 3, "id": "orig-sess"}),
user_line("u1", "", "2026-08-31T00:00:00Z", "prompt"),
assistant_line(
"a1",
"u1",
"2026-08-31T00:00:05Z",
"model-x",
"answer",
100,
10,
0,
0.001
),
);
let fork = format!(
"{}\n{}\n{}\n{}",
json!({"type": "session", "version": 3, "id": "fork-sess"}),
user_line("u1", "", "2026-08-31T00:00:00Z", "prompt"),
user_line("u2", "u1", "2026-08-31T00:00:02Z", "extra turn"),
assistant_line(
"a1",
"u2",
"2026-08-31T00:00:05Z",
"model-x",
"answer",
100,
10,
0,
0.001
),
);
let orig_path = write_session(&dir, "proj", "orig", &original);
let fork_path = write_session(&dir, "proj", "fork", &fork);
let mut seen = std::collections::HashSet::new();
let mut merged: Vec<UnifiedMessage> = Vec::new();
for path in [orig_path, fork_path] {
for msg in parse_commandcode_file(&path) {
let keep = msg
.dedup_key
.as_ref()
.is_none_or(|key| seen.insert(key.clone()));
if keep {
merged.push(msg);
}
}
}
let assistant_msgs: Vec<_> = merged.iter().filter(|m| m.model_id == "model-x").collect();
assert_eq!(
assistant_msgs.len(),
1,
"fork copy of the same entry must collapse to one message"
);
assert_eq!(assistant_msgs[0].tokens.input, 100);
}
#[test]
fn test_fork_with_missing_timestamp_still_dedups() {
let dir = TempDir::new().unwrap();
write_config(&dir, "model-x");
let make_session = |session_id: &str| {
format!(
"{}\n{}\n{}",
json!({"type": "session", "version": 3, "id": session_id}),
json!({
"type": "message",
"id": "u1",
"parentId": null,
"message": {"role": "user", "content": [{"type": "text", "text": "prompt"}]}
}),
json!({
"type": "message",
"id": "a1",
"parentId": "u1",
"message": {"role": "assistant", "content": [{"type": "text", "text": "answer"}]},
"usage": {
"inputTokens": 100,
"outputTokens": 10,
"cacheReadTokens": 0,
"cacheWriteTokens": 0,
"costUsd": 0.001
},
"model": "model-x"
}),
)
};
let original = make_session("orig-sess");
let orig_path = write_session(&dir, "proj", "orig", &original);
std::thread::sleep(std::time::Duration::from_millis(1100));
let fork = make_session("fork-sess");
let fork_path = write_session(&dir, "proj", "fork", &fork);
let mut seen = std::collections::HashSet::new();
let mut merged: Vec<UnifiedMessage> = Vec::new();
for path in [orig_path, fork_path] {
for msg in parse_commandcode_file(&path) {
let keep = msg
.dedup_key
.as_ref()
.is_none_or(|key| seen.insert(key.clone()));
if keep {
merged.push(msg);
}
}
}
let assistant_msgs: Vec<_> = merged.iter().filter(|m| m.model_id == "model-x").collect();
assert_eq!(
assistant_msgs.len(),
1,
"fork copy without timestamps must still collapse to one message"
);
assert_eq!(assistant_msgs[0].tokens.input, 100);
}
#[test]
fn test_parse_v3_transcript_with_authoritative_usage() {
let dir = TempDir::new().unwrap();
write_config(&dir, "deepseek/deepseek-v4-flash");
let jsonl = format!(
"{}\n{}\n{}",
json!({"type": "session", "version": 3, "id": "sess-1", "cwd": "/home/al/learning"}),
user_line("u1", "", "2026-08-31T04:39:16.867Z", "hello"),
assistant_line(
"a1",
"u1",
"2026-08-31T04:39:20.351Z",
"deepseek/deepseek-v4-flash",
"hi there",
28534,
205,
7424,
0.006464748
),
);
let path = write_session(&dir, "home-al-learning", "sess-1", &jsonl);
let messages = parse_commandcode_file(&path);
assert_eq!(messages.len(), 1);
let msg = &messages[0];
assert_eq!(msg.client, "commandcode");
assert_eq!(msg.provider_id, "deepseek");
assert_eq!(msg.model_id, "deepseek-v4-flash");
assert_eq!(msg.session_id, "sess-1");
assert_eq!(msg.tokens.input, 28534);
assert_eq!(msg.tokens.output, 205);
assert_eq!(msg.tokens.cache_read, 7424);
assert_eq!(msg.tokens.cache_write, 0);
assert_eq!(msg.tokens.reasoning, 0);
assert_eq!(msg.tokens.total(), 36163); assert!((msg.cost - 0.006464748).abs() < 1e-9);
assert!(msg.has_authoritative_cost());
assert!(msg.is_turn_start);
assert_eq!(msg.message_count, 1);
assert_eq!(msg.timestamp, 1788151160351); assert_eq!(msg.workspace_key.as_deref(), Some("home-al-learning"));
}
#[test]
fn test_parse_v3_transcript_model_change_updates_model() {
let dir = TempDir::new().unwrap();
write_config(&dir, "deepseek/deepseek-v4-flash");
let jsonl = format!(
"{}\n{}\n{}\n{}",
json!({"type": "session", "version": 3, "id": "sess-1"}),
json!({"type": "model_change", "id": "m1", "parentId": null, "timestamp": "2026-08-31T03:32:29.603Z", "model": "minimax/minimax-m3-free"}),
user_line("u1", "m1", "2026-08-31T03:33:00.000Z", "first"),
assistant_line(
"a1",
"u1",
"2026-08-31T03:33:05.000Z",
"minimax/minimax-m3-free",
"resp one",
100,
10,
0,
0.001
),
);
let path = write_session(&dir, "proj", "sess-1", &jsonl);
let messages = parse_commandcode_file(&path);
assert_eq!(messages.len(), 1);
assert_eq!(messages[0].model_id, "minimax-m3-free");
assert_eq!(messages[0].provider_id, "minimax");
}
#[test]
fn test_canonicalize_model_strips_org_prefix_only() {
assert_eq!(
canonicalize_model("MiniMaxAI/MiniMax-M3-Free"),
"MiniMax-M3-Free"
);
assert_eq!(
canonicalize_model("minimaxai/minimax-m3-free"),
"minimax-m3-free"
);
assert_eq!(canonicalize_model("MiniMaxAI/MiniMax-M2.5"), "MiniMax-M2.5");
assert_eq!(canonicalize_model("taste-1"), "taste-1");
assert_eq!(
canonicalize_model("poolside/laguna-s-2.1-free"),
"laguna-s-2.1-free"
);
}
#[test]
fn test_canonicalize_model_does_not_panic_on_non_ascii() {
assert_eq!(canonicalize_model("vendor/modèle"), "modèle");
assert_eq!(canonicalize_model("café-🚀"), "café-🚀");
assert_eq!(canonicalize_model("café-free"), "café-free");
}
#[test]
fn test_content_chars_counts_keys_numbers_and_nested_payloads() {
assert!(content_chars(&json!([{"value": 12345}])) > 0);
let small = content_chars(&json!([{"a": "x"}]));
let large = content_chars(&json!([{"command": "run", "args": ["a", "b"], "n": 42}]));
assert!(large > small);
}
#[test]
fn test_checkpoint_files_are_skipped() {
let dir = TempDir::new().unwrap();
write_config(&dir, "model-x");
let project_dir = dir.path().join("projects").join("proj");
std::fs::create_dir_all(&project_dir).unwrap();
let path = project_dir.join("s.checkpoints.jsonl");
let mut file = std::fs::File::create(&path).unwrap();
file.write_all(
br#"{"type":"checkpoint","messageId":"m","snapshot":"snap","isSnapshotUpdate":false}"#,
)
.unwrap();
let messages = parse_commandcode_file(&path);
assert!(messages.is_empty());
}
#[test]
fn test_missing_config_and_model_falls_back_to_unknown_model() {
let dir = TempDir::new().unwrap();
let jsonl = format!(
"{}\n{}\n{}",
json!({"type": "session", "version": 3, "id": "s"}),
user_line("u1", "", "2026-08-31T00:00:00Z", "hello"),
assistant_line(
"a1",
"u1",
"2026-08-31T00:00:05Z",
"",
"world",
10,
5,
0,
0.0
),
);
let path = write_session(&dir, "proj", "s", &jsonl);
let messages = parse_commandcode_file(&path);
assert_eq!(messages.len(), 1);
assert_eq!(messages[0].model_id, "unknown");
assert_eq!(messages[0].provider_id, "command-code");
}
#[test]
fn test_skips_malformed_lines_without_panicking() {
let dir = TempDir::new().unwrap();
write_config(&dir, "model-x");
let jsonl = concat!(
"not valid json at all\n",
r#"{"type":"session","version":3,"id":"s"}"#,
"\n",
);
let path = write_session(&dir, "proj", "s", jsonl);
let messages = parse_commandcode_file(&path);
assert!(messages.is_empty());
}
#[test]
fn test_estimated_fallback_when_usage_absent() {
let dir = TempDir::new().unwrap();
write_config(&dir, "model-x");
let jsonl = format!(
"{}\n{}\n{}",
json!({"type": "session", "version": 3, "id": "s"}),
json!({
"type": "message",
"id": "u1",
"parentId": null,
"timestamp": "2026-08-31T00:00:00Z",
"message": {"role": "user", "content": [{"type": "text", "text": "12345678"}]}
}),
json!({
"type": "message",
"id": "a1",
"parentId": "u1",
"timestamp": "2026-08-31T00:00:05Z",
"message": {"role": "assistant", "content": [{"type": "text", "text": "abcd"}]},
"model": "model-x"
}),
);
let path = write_session(&dir, "proj", "s", &jsonl);
let messages = parse_commandcode_file(&path);
assert_eq!(messages.len(), 1);
let msg = &messages[0];
assert_eq!(
msg.tokens.input,
estimate_tokens(content_chars(
&json!([{"type": "text", "text": "12345678"}])
))
);
assert_eq!(
msg.tokens.output,
estimate_tokens(content_chars(&json!([{"type": "text", "text": "abcd"}])))
);
assert_eq!(msg.cost, 0.0);
assert!(!msg.has_authoritative_cost());
assert!(msg.is_turn_start);
}
#[test]
fn test_explicit_zero_cost_is_provider_reported() {
let dir = TempDir::new().unwrap();
write_config(&dir, "minimax/minimax-m3-free");
let jsonl = format!(
"{}\n{}\n{}",
json!({"type": "session", "version": 3, "id": "s"}),
user_line("u1", "", "2026-08-31T00:00:00Z", "hi"),
json!({
"type": "message",
"id": "a1",
"parentId": "u1",
"timestamp": "2026-08-31T00:00:05Z",
"message": {"role": "assistant", "content": [{"type": "text", "text": "yo"}]},
"usage": {
"inputTokens": 100,
"outputTokens": 10,
"cacheReadTokens": 0,
"cacheWriteTokens": 0,
"costUsd": 0
},
"model": "minimax/minimax-m3-free"
}),
);
let path = write_session(&dir, "proj", "s", &jsonl);
let messages = parse_commandcode_file(&path);
assert_eq!(messages.len(), 1);
let msg = &messages[0];
assert_eq!(msg.cost, 0.0);
assert!(
msg.has_authoritative_cost(),
"an explicit zero cost is provider-reported, not repriced"
);
assert_eq!(msg.model_id, "minimax-m3-free");
}
#[test]
fn test_usage_buckets_are_disjoint() {
let dir = TempDir::new().unwrap();
write_config(&dir, "model-x");
let jsonl = format!(
"{}\n{}\n{}",
json!({"type": "session", "version": 3, "id": "s"}),
user_line("u1", "", "2026-08-31T00:00:00Z", "hi"),
json!({
"type": "message",
"id": "a1",
"parentId": "u1",
"timestamp": "2026-08-31T00:00:05Z",
"message": {"role": "assistant", "content": [{"type": "text", "text": "yo"}]},
"usage": {
"inputTokens": 1000,
"outputTokens": 50,
"cacheReadTokens": 900,
"cacheWriteTokens": 10,
"costUsd": 0.01
},
"model": "model-x"
}),
);
let path = write_session(&dir, "proj", "s", &jsonl);
let messages = parse_commandcode_file(&path);
assert_eq!(messages.len(), 1);
let msg = &messages[0];
assert_eq!(msg.tokens.input, 1000);
assert_eq!(msg.tokens.cache_read, 900);
assert_eq!(msg.tokens.cache_write, 10);
assert_eq!(msg.tokens.total(), 1960);
}
#[test]
fn test_all_zero_usage_block_is_not_estimated_or_marked_provider_reported() {
let dir = TempDir::new().unwrap();
write_config(&dir, "model-x");
let long_prompt = "x".repeat(4000);
let long_answer = "y".repeat(4000);
let zero_usage_line = |cost: serde_json::Value| {
json!({
"type": "message",
"id": "a1",
"parentId": "u1",
"timestamp": "2026-08-31T00:00:05Z",
"message": {"role": "assistant", "content": [{"type": "text", "text": long_answer}]},
"usage": {
"inputTokens": 0,
"outputTokens": 0,
"cacheReadTokens": 0,
"cacheWriteTokens": 0,
"costUsd": cost
},
"model": "model-x"
})
.to_string()
};
let with_zero_cost = format!(
"{}\n{}\n{}",
json!({"type": "session", "version": 3, "id": "s"}),
user_line("u1", "", "2026-08-31T00:00:00Z", &long_prompt),
zero_usage_line(json!(0)),
);
let path = write_session(&dir, "proj", "zero-cost", &with_zero_cost);
let messages = parse_commandcode_file(&path);
assert!(
messages.is_empty(),
"a reported all-zero turn must emit nothing, not estimated tokens; got {:?}",
messages
.iter()
.map(|m| (m.tokens.total(), m.cost, m.has_authoritative_cost()))
.collect::<Vec<_>>()
);
let without_cost = format!(
"{}\n{}\n{}",
json!({"type": "session", "version": 3, "id": "s"}),
user_line("u1", "", "2026-08-31T00:00:00Z", &long_prompt),
zero_usage_line(serde_json::Value::Null),
);
let path = write_session(&dir, "proj", "no-cost", &without_cost);
let messages = parse_commandcode_file(&path);
assert!(
messages.is_empty(),
"an all-zero block without costUsd is still authoritative; got {:?}",
messages
.iter()
.map(|m| (m.tokens.total(), m.cost))
.collect::<Vec<_>>()
);
}
#[test]
fn test_partial_usage_block_is_authoritative_not_estimated() {
let dir = TempDir::new().unwrap();
write_config(&dir, "model-x");
let jsonl = format!(
"{}\n{}\n{}",
json!({"type": "session", "version": 3, "id": "s"}),
user_line("u1", "", "2026-08-31T00:00:00Z", &"p".repeat(4000)),
json!({
"type": "message",
"id": "a1",
"parentId": "u1",
"timestamp": "2026-08-31T00:00:05Z",
"message": {"role": "assistant", "content": [{"type": "text", "text": "short"}]},
"usage": {"outputTokens": 7, "costUsd": 0.25},
"model": "model-x"
}),
);
let path = write_session(&dir, "proj", "s", &jsonl);
let messages = parse_commandcode_file(&path);
assert_eq!(messages.len(), 1);
let msg = &messages[0];
assert_eq!(msg.tokens.input, 0);
assert_eq!(msg.tokens.output, 7);
assert_eq!(msg.tokens.cache_read, 0);
assert_eq!(msg.tokens.cache_write, 0);
assert!((msg.cost - 0.25).abs() < 1e-9);
assert!(msg.has_authoritative_cost());
}
#[test]
fn test_turn_start_survives_dropped_all_zero_authoritative_line() {
let dir = TempDir::new().unwrap();
write_config(&dir, "model-x");
let jsonl = format!(
"{}\n{}\n{}\n{}",
json!({"type": "session", "version": 3, "id": "s"}),
user_line("u1", "", "2026-08-31T00:00:00Z", "hi"),
json!({
"type": "message",
"id": "a1",
"parentId": "u1",
"timestamp": "2026-08-31T00:00:05Z",
"message": {"role": "assistant", "content": [{"type": "text", "text": "aborted"}]},
"usage": {
"inputTokens": 0,
"outputTokens": 0,
"cacheReadTokens": 0,
"cacheWriteTokens": 0,
"costUsd": 0
},
"model": "model-x"
}),
assistant_line(
"a2",
"a1",
"2026-08-31T00:00:09Z",
"model-x",
"the real response",
10,
5,
0,
0.001
),
);
let path = write_session(&dir, "proj", "s", &jsonl);
let messages = parse_commandcode_file(&path);
assert_eq!(messages.len(), 1, "the all-zero line must not be emitted");
let msg = &messages[0];
assert_eq!(msg.tokens.input, 10);
assert_eq!(msg.tokens.output, 5);
assert!(
msg.is_turn_start,
"the turn started by u1 must be marked on the surviving response"
);
}
#[test]
fn test_turn_start_survives_dropped_zero_assistant_line() {
let dir = TempDir::new().unwrap();
write_config(&dir, "model-x");
let jsonl = format!(
"{}\n{}\n{}\n{}",
json!({"type": "session", "version": 3, "id": "s"}),
json!({
"type": "message",
"id": "a0",
"parentId": null,
"timestamp": "2026-08-31T00:00:01Z",
"message": {"role": "assistant", "content": []}
}),
user_line("u1", "a0", "2026-08-31T00:00:02Z", "hi"),
assistant_line(
"a1",
"u1",
"2026-08-31T00:00:05Z",
"model-x",
"response",
10,
5,
0,
0.0
),
);
let path = write_session(&dir, "proj", "s", &jsonl);
let messages = parse_commandcode_file(&path);
assert_eq!(messages.len(), 1);
assert!(messages[0].is_turn_start);
}
#[test]
fn test_legacy_flat_schema_still_parses_with_estimation() {
let dir = TempDir::new().unwrap();
write_config(&dir, "MiniMaxAI/MiniMax-M3-Free");
let jsonl = concat!(
r#"{"role":"user","sessionId":"legacy-session-42","content":[{"type":"text","text":"12345678"}]}"#,
"\n",
r#"{"role":"assistant","sessionId":"legacy-session-42","content":[{"type":"text","text":"abcd"}]}"#,
);
let path = write_session(&dir, "proj", "sess-1", jsonl);
let messages = parse_commandcode_file(&path);
assert_eq!(messages.len(), 1);
let msg = &messages[0];
assert_eq!(msg.client, "commandcode");
assert_eq!(msg.model_id, "MiniMax-M3-Free");
assert_eq!(msg.provider_id, "minimax");
assert_eq!(msg.session_id, "legacy-session-42");
assert_eq!(
msg.tokens.input,
estimate_tokens(content_chars(
&json!([{"type": "text", "text": "12345678"}])
))
);
assert_eq!(
msg.tokens.output,
estimate_tokens(content_chars(&json!([{"type": "text", "text": "abcd"}])))
);
assert!(!msg.has_authoritative_cost());
}
#[test]
fn test_all_zero_usage_with_positive_cost_is_kept() {
let dir = TempDir::new().unwrap();
write_config(&dir, "model-x");
let jsonl = format!(
"{}\n{}\n{}",
json!({"type": "session", "version": 3, "id": "s"}),
user_line("u1", "", "2026-08-31T00:00:00Z", "hi"),
json!({
"type": "message",
"id": "a1",
"parentId": "u1",
"timestamp": "2026-08-31T00:00:05Z",
"message": {
"role": "assistant",
"content": [{"type": "text", "text": "billed per request"}]
},
"usage": {
"inputTokens": 0,
"outputTokens": 0,
"cacheReadTokens": 0,
"cacheWriteTokens": 0,
"costUsd": 0.42
},
"model": "model-x"
}),
);
let path = write_session(&dir, "proj", "s", &jsonl);
let messages = parse_commandcode_file(&path);
assert_eq!(messages.len(), 1, "a billed turn must not be dropped");
let msg = &messages[0];
assert_eq!(
msg.tokens.total(),
0,
"the provider's zero buckets are kept verbatim, not estimated"
);
assert_eq!(msg.cost, 0.42);
assert!(
msg.has_authoritative_cost(),
"the recorded charge stays provider-reported"
);
}
#[test]
fn test_legacy_positional_dedup_keys_differ_across_projects() {
let dir = TempDir::new().unwrap();
write_config(&dir, "model-x");
let jsonl = concat!(
r#"{"role":"user","content":[{"type":"text","text":"12345678"}]}"#,
"\n",
r#"{"role":"assistant","content":[{"type":"text","text":"abcd"}]}"#,
);
let a = write_session(&dir, "project-a", "chat", jsonl);
let b = write_session(&dir, "project-b", "chat", jsonl);
let keys = |path: &std::path::Path| {
parse_commandcode_file(path)
.into_iter()
.map(|m| {
m.dedup_key
.expect("a legacy line still gets a positional dedup key")
})
.collect::<Vec<_>>()
};
let keys_a = keys(&a);
let keys_b = keys(&b);
assert_eq!(keys_a.len(), 1);
assert_eq!(keys_b.len(), 1);
assert_ne!(
keys_a[0], keys_b[0],
"identically-named legacy sessions in different projects must not share a dedup key"
);
}
#[test]
fn test_empty_usage_block_falls_back_to_estimation() {
let dir = TempDir::new().unwrap();
write_config(&dir, "model-x");
let jsonl = format!(
"{}\n{}\n{}",
json!({"type": "session", "version": 3, "id": "s"}),
user_line("u1", "", "2026-08-31T00:00:00Z", "12345678"),
json!({
"type": "message",
"id": "a1",
"parentId": "u1",
"timestamp": "2026-08-31T00:00:05Z",
"message": {"role": "assistant", "content": [{"type": "text", "text": "abcd"}]},
"usage": {},
"model": "model-x"
}),
);
let path = write_session(&dir, "proj", "s", &jsonl);
let messages = parse_commandcode_file(&path);
assert_eq!(messages.len(), 1);
let msg = &messages[0];
assert_eq!(
msg.tokens.input,
estimate_tokens(content_chars(
&json!([{"type": "text", "text": "12345678"}])
))
);
assert_eq!(
msg.tokens.output,
estimate_tokens(content_chars(&json!([{"type": "text", "text": "abcd"}])))
);
assert!(!msg.has_authoritative_cost());
}
#[test]
fn test_adversarial_usage_values_are_clamped() {
let dir = TempDir::new().unwrap();
write_config(&dir, "model-x");
let jsonl = format!(
"{}\n{}\n{}",
json!({"type": "session", "version": 3, "id": "s"}),
user_line("u1", "", "2026-08-31T00:00:00Z", "hi"),
json!({
"type": "message",
"id": "a1",
"parentId": "u1",
"timestamp": "2026-08-31T00:00:05Z",
"message": {"role": "assistant", "content": [{"type": "text", "text": "yo"}]},
"usage": {
"inputTokens": 9223372036854775807i64,
"outputTokens": 9223372036854775807i64,
"cacheReadTokens": 9223372036854775807i64,
"cacheWriteTokens": 9223372036854775807i64,
"costUsd": 1.0e300
},
"model": "model-x"
}),
);
let path = write_session(&dir, "proj", "s", &jsonl);
let messages = parse_commandcode_file(&path);
assert_eq!(messages.len(), 1);
let msg = &messages[0];
assert_eq!(msg.tokens.input, 1_000_000_000_000);
assert_eq!(msg.tokens.output, 1_000_000_000_000);
assert_eq!(msg.tokens.cache_read, 1_000_000_000_000);
assert_eq!(msg.tokens.total(), 4_000_000_000_000);
assert_eq!(msg.cost, 0.0);
assert!(!msg.has_authoritative_cost());
}
}