fix: ensure permission/stats persist until explicit disconnect #110

Merged
naomi merged 7 commits from fix/perms into main 2026-02-06 13:54:31 -08:00
4 changed files with 26 additions and 20 deletions
Showing only changes of commit dfb1ab36ce - Show all commits
+4
View File
@@ -2329,6 +2329,10 @@ mod tests {
context_utilisation_percent: 0.0,
potential_cache_hits: 0,
potential_cache_savings_tokens: 0,
current_request_input: None,
current_request_output_chars: 0,
current_request_thinking_chars: 0,
current_request_tools: Vec::new(),
achievements: AchievementProgress::new(),
}
}
+18 -18
View File
@@ -658,7 +658,7 @@ mod tests {
#[test]
fn test_cost_calculation_sonnet() {
let cost = calculate_cost(1000, 2000, "claude-sonnet-4-20250514");
let cost = calculate_cost(1000, 2000, "claude-sonnet-4-20250514", None, None);
// 1000 input * $3/M = $0.003
// 2000 output * $15/M = $0.030
// Total = $0.033
@@ -667,7 +667,7 @@ mod tests {
#[test]
fn test_cost_calculation_opus() {
let cost = calculate_cost(1000, 2000, "claude-opus-4-20250514");
let cost = calculate_cost(1000, 2000, "claude-opus-4-20250514", None, None);
// 1000 input * $15/M = $0.015
// 2000 output * $75/M = $0.150
// Total = $0.165
@@ -676,7 +676,7 @@ mod tests {
#[test]
fn test_cost_calculation_opus_45() {
let cost = calculate_cost(1000, 2000, "claude-opus-4-5-20251101");
let cost = calculate_cost(1000, 2000, "claude-opus-4-5-20251101", None, None);
// Opus 4.5 pricing: $5/MTok input, $25/MTok output
// 1000 input tokens = $0.005, 2000 output tokens = $0.05
// Total = $0.055
@@ -685,7 +685,7 @@ mod tests {
#[test]
fn test_cost_calculation_haiku() {
let cost = calculate_cost(1000, 2000, "claude-3-5-haiku-20241022");
let cost = calculate_cost(1000, 2000, "claude-3-5-haiku-20241022", None, None);
// 1000 input * $1/M = $0.001
// 2000 output * $5/M = $0.010
// Total = $0.011
@@ -694,14 +694,14 @@ mod tests {
#[test]
fn test_cost_calculation_unknown_defaults_to_sonnet() {
let cost = calculate_cost(1000, 2000, "some-unknown-model");
let cost = calculate_cost(1000, 2000, "some-unknown-model", None, None);
// Should default to Sonnet pricing
assert!((cost - 0.033).abs() < 0.0001);
}
#[test]
fn test_cost_calculation_legacy_sonnet() {
let cost = calculate_cost(1000, 2000, "claude-3-5-sonnet-20241022");
let cost = calculate_cost(1000, 2000, "claude-3-5-sonnet-20241022", None, None);
// Same as Sonnet 4 pricing
assert!((cost - 0.033).abs() < 0.0001);
}
@@ -709,7 +709,7 @@ mod tests {
#[test]
fn test_usage_stats_accumulation() {
let mut stats = UsageStats::new();
stats.add_usage(1000, 2000, "claude-sonnet-4-20250514");
stats.add_usage(1000, 2000, "claude-sonnet-4-20250514", None, None);
assert_eq!(stats.total_input_tokens, 1000);
assert_eq!(stats.total_output_tokens, 2000);
@@ -721,8 +721,8 @@ mod tests {
#[test]
fn test_usage_stats_multiple_accumulations() {
let mut stats = UsageStats::new();
stats.add_usage(1000, 1000, "claude-sonnet-4-20250514");
stats.add_usage(500, 500, "claude-sonnet-4-20250514");
stats.add_usage(1000, 1000, "claude-sonnet-4-20250514", None, None);
stats.add_usage(500, 500, "claude-sonnet-4-20250514", None, None);
assert_eq!(stats.total_input_tokens, 1500);
assert_eq!(stats.total_output_tokens, 1500);
@@ -733,17 +733,17 @@ mod tests {
#[test]
fn test_usage_stats_model_updated() {
let mut stats = UsageStats::new();
stats.add_usage(1000, 1000, "claude-sonnet-4-20250514");
stats.add_usage(1000, 1000, "claude-sonnet-4-20250514", None, None);
assert_eq!(stats.model, Some("claude-sonnet-4-20250514".to_string()));
stats.add_usage(500, 500, "claude-opus-4-20250514");
stats.add_usage(500, 500, "claude-opus-4-20250514", None, None);
assert_eq!(stats.model, Some("claude-opus-4-20250514".to_string()));
}
#[test]
fn test_session_reset() {
let mut stats = UsageStats::new();
stats.add_usage(1000, 2000, "claude-sonnet-4-20250514");
stats.add_usage(1000, 2000, "claude-sonnet-4-20250514", None, None);
stats.reset_session();
assert_eq!(stats.total_input_tokens, 1000);
@@ -970,7 +970,7 @@ mod tests {
#[test]
fn test_usage_stats_serialization() {
let mut stats = UsageStats::new();
stats.add_usage(1000, 2000, "claude-sonnet-4-20250514");
stats.add_usage(1000, 2000, "claude-sonnet-4-20250514", None, None);
stats.increment_messages();
// UsageStats should be serializable (for events)
@@ -999,7 +999,7 @@ mod tests {
#[test]
fn test_stats_update_event_serialization() {
let mut stats = UsageStats::new();
stats.add_usage(100, 200, "claude-sonnet-4-20250514");
stats.add_usage(100, 200, "claude-sonnet-4-20250514", None, None);
let event = StatsUpdateEvent { stats };
let json = serde_json::to_string(&event).expect("Failed to serialize");
@@ -1053,7 +1053,7 @@ mod tests {
#[test]
fn test_context_tracking_update() {
let mut stats = UsageStats::new();
stats.add_usage(50_000, 10_000, "claude-sonnet-4-20250514");
stats.add_usage(50_000, 10_000, "claude-sonnet-4-20250514", None, None);
assert_eq!(stats.context_tokens_used, 50_000);
assert_eq!(stats.context_window_limit, 200_000);
@@ -1063,8 +1063,8 @@ mod tests {
#[test]
fn test_context_tracking_accumulates() {
let mut stats = UsageStats::new();
stats.add_usage(50_000, 10_000, "claude-sonnet-4-20250514");
stats.add_usage(50_000, 10_000, "claude-sonnet-4-20250514");
stats.add_usage(50_000, 10_000, "claude-sonnet-4-20250514", None, None);
stats.add_usage(50_000, 10_000, "claude-sonnet-4-20250514", None, None);
assert_eq!(stats.context_tokens_used, 100_000);
assert!((stats.context_utilisation_percent - 50.0).abs() < 0.1);
@@ -1128,7 +1128,7 @@ mod tests {
#[test]
fn test_context_reset_on_session_reset() {
let mut stats = UsageStats::new();
stats.add_usage(100_000, 20_000, "claude-sonnet-4-20250514");
stats.add_usage(100_000, 20_000, "claude-sonnet-4-20250514", None, None);
assert!(stats.context_tokens_used > 0);
assert!(stats.context_utilisation_percent > 0.0);
+1 -1
View File
@@ -498,7 +498,7 @@ impl WslBridge {
if tool_stats.call_count > 0 {
// Use session average tokens per call for this tool
let avg_tokens = (tool_stats.estimated_input_tokens + tool_stats.estimated_output_tokens)
/ tool_stats.call_count as u64;
/ tool_stats.call_count;
tool_overhead_tokens += avg_tokens;
println!("[COST ESTIMATION] Tool {} average: {} tokens", tool_name, avg_tokens);
}
+3 -1
View File
@@ -341,7 +341,9 @@ User: ${formattedMessage}`;
// Get current working directory and granted tools before reconnecting
const workingDir = await invoke<string>("get_working_directory", { conversationId });
const activeConversation = get(conversationsStore.activeConversation);
const grantedTools = activeConversation ? Array.from(activeConversation.grantedTools) : [];
const grantedTools = activeConversation
? Array.from(activeConversation.grantedTools)
: [];
const config = configStore.getConfig();
const allAllowedTools = [...new Set([...grantedTools, ...config.auto_granted_tools])];