Skip to content

Commit b624590

Browse files
author
jack
committed
fix: resolve clippy warnings and finalize async token counter
- Fixed needless borrow warnings in context.rs - Added blocking feature to reqwest for backward compatibility - Moved demo file to proper examples directory - Applied cargo fmt formatting - All tests pass successfully
1 parent 95e5e8c commit b624590

6 files changed

Lines changed: 174 additions & 61 deletions

File tree

crates/goose/Cargo.toml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ reqwest = { version = "0.12.9", features = [
3131
"zstd",
3232
"charset",
3333
"http2",
34-
"stream"
34+
"stream",
35+
"blocking"
3536
], default-features = false }
3637
tokio = { version = "1.43", features = ["full"] }
3738
serde = { version = "1.0", features = ["derive"] }
@@ -109,6 +110,10 @@ path = "examples/agent.rs"
109110
name = "databricks_oauth"
110111
path = "examples/databricks_oauth.rs"
111112

113+
[[example]]
114+
name = "async_token_counter_demo"
115+
path = "examples/async_token_counter_demo.rs"
116+
112117
[[bench]]
113118
name = "tokenization_benchmark"
114119
harness = false

async_token_counter_demo.rs renamed to crates/goose/examples/async_token_counter_demo.rs

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,30 @@
11
/// Demo showing the async token counter improvement
2-
///
2+
///
33
/// This example demonstrates the key improvement: no blocking runtime creation
4-
///
5-
/// BEFORE (blocking):
4+
///
5+
/// BEFORE (blocking):
66
/// ```rust
77
/// let content = tokio::runtime::Runtime::new()?.block_on(async {
88
/// let response = reqwest::get(&file_url).await?;
99
/// // ... download logic
1010
/// })?;
1111
/// ```
12-
///
12+
///
1313
/// AFTER (async):
1414
/// ```rust
1515
/// let client = reqwest::Client::new();
1616
/// let response = client.get(&file_url).send().await?;
1717
/// let bytes = response.bytes().await?;
1818
/// tokio::fs::write(&file_path, bytes).await?;
1919
/// ```
20-
21-
use goose::token_counter::{TokenCounter, AsyncTokenCounter, create_async_token_counter};
20+
use goose::token_counter::{create_async_token_counter, TokenCounter};
2221
use std::time::Instant;
2322

2423
#[tokio::main]
2524
async fn main() -> Result<(), Box<dyn std::error::Error>> {
2625
println!("🚀 Async Token Counter Demo");
2726
println!("===========================");
28-
27+
2928
// Test text samples
3029
let samples = vec![
3130
"Hello, world!",
@@ -34,70 +33,72 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
3433
"Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
3534
"async/await patterns eliminate blocking operations",
3635
];
37-
36+
3837
println!("\n📊 Performance Comparison");
3938
println!("-------------------------");
40-
39+
4140
// Test original TokenCounter
4241
let start = Instant::now();
4342
let sync_counter = TokenCounter::new("Xenova--gpt-4o");
4443
let sync_init_time = start.elapsed();
45-
44+
4645
let start = Instant::now();
4746
let mut sync_total = 0;
4847
for sample in &samples {
4948
sync_total += sync_counter.count_tokens(sample);
5049
}
5150
let sync_count_time = start.elapsed();
52-
51+
5352
println!("🔴 Synchronous TokenCounter:");
5453
println!(" Init time: {:?}", sync_init_time);
5554
println!(" Count time: {:?}", sync_count_time);
5655
println!(" Total tokens: {}", sync_total);
57-
58-
// Test AsyncTokenCounter
56+
57+
// Test AsyncTokenCounter
5958
let start = Instant::now();
6059
let async_counter = create_async_token_counter("Xenova--gpt-4o").await?;
6160
let async_init_time = start.elapsed();
62-
61+
6362
let start = Instant::now();
6463
let mut async_total = 0;
6564
for sample in &samples {
6665
async_total += async_counter.count_tokens(sample);
6766
}
6867
let async_count_time = start.elapsed();
69-
68+
7069
println!("\n🟢 Async TokenCounter:");
7170
println!(" Init time: {:?}", async_init_time);
7271
println!(" Count time: {:?}", async_count_time);
7372
println!(" Total tokens: {}", async_total);
7473
println!(" Cache size: {}", async_counter.cache_size());
75-
74+
7675
// Test caching benefit
7776
let start = Instant::now();
7877
let mut cached_total = 0;
7978
for sample in &samples {
8079
cached_total += async_counter.count_tokens(sample); // Should hit cache
8180
}
8281
let cached_time = start.elapsed();
83-
82+
8483
println!("\n⚡ Cached TokenCounter (2nd run):");
8584
println!(" Count time: {:?}", cached_time);
8685
println!(" Total tokens: {}", cached_total);
8786
println!(" Cache size: {}", async_counter.cache_size());
88-
87+
8988
// Verify same results
9089
assert_eq!(sync_total, async_total);
9190
assert_eq!(async_total, cached_total);
92-
91+
9392
println!("\n✅ Key Improvements:");
9493
println!(" • No blocking runtime creation (eliminates deadlock risk)");
9594
println!(" • Global tokenizer caching with DashMap (lock-free concurrent access)");
9695
println!(" • Fast AHash for better cache performance");
9796
println!(" • Cache size management (prevents unbounded growth)");
98-
println!(" • Token result caching ({}x faster on repeated text)",
99-
async_count_time.as_nanos() / cached_time.as_nanos().max(1));
97+
println!(
98+
" • Token result caching ({}x faster on repeated text)",
99+
async_count_time.as_nanos() / cached_time.as_nanos().max(1)
100+
);
100101
println!(" • Proper async patterns throughout");
101-
102+
102103
Ok(())
103-
}
104+
}

crates/goose/src/agents/context.rs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,10 @@ impl Agent {
1616
messages: &[Message], // last message is a user msg that led to assistant message with_context_length_exceeded
1717
) -> Result<(Vec<Message>, Vec<usize>), anyhow::Error> {
1818
let provider = self.provider().await?;
19-
let token_counter = create_async_token_counter(&provider.get_model_config().tokenizer_name()).await
20-
.map_err(|e| anyhow::anyhow!("Failed to create token counter: {}", e))?;
19+
let token_counter =
20+
create_async_token_counter(provider.get_model_config().tokenizer_name())
21+
.await
22+
.map_err(|e| anyhow::anyhow!("Failed to create token counter: {}", e))?;
2123
let target_context_limit = estimate_target_context_limit(provider);
2224
let token_counts = get_messages_token_counts_async(&token_counter, messages);
2325

@@ -52,12 +54,15 @@ impl Agent {
5254
messages: &[Message], // last message is a user msg that led to assistant message with_context_length_exceeded
5355
) -> Result<(Vec<Message>, Vec<usize>), anyhow::Error> {
5456
let provider = self.provider().await?;
55-
let token_counter = create_async_token_counter(&provider.get_model_config().tokenizer_name()).await
56-
.map_err(|e| anyhow::anyhow!("Failed to create token counter: {}", e))?;
57+
let token_counter =
58+
create_async_token_counter(provider.get_model_config().tokenizer_name())
59+
.await
60+
.map_err(|e| anyhow::anyhow!("Failed to create token counter: {}", e))?;
5761
let target_context_limit = estimate_target_context_limit(provider.clone());
5862

5963
let (mut new_messages, mut new_token_counts) =
60-
summarize_messages_async(provider, messages, &token_counter, target_context_limit).await?;
64+
summarize_messages_async(provider, messages, &token_counter, target_context_limit)
65+
.await?;
6166

6267
// If the summarized messages only contains one message, it means no tool request and response message in the summarized messages,
6368
// Add an assistant message to the summarized messages to ensure the assistant's response is included in the context.

crates/goose/src/context_mgmt/common.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@ use std::sync::Arc;
22

33
use mcp_core::Tool;
44

5-
use crate::{message::Message, providers::base::Provider, token_counter::{TokenCounter, AsyncTokenCounter}};
5+
use crate::{
6+
message::Message,
7+
providers::base::Provider,
8+
token_counter::{AsyncTokenCounter, TokenCounter},
9+
};
610

711
const ESTIMATE_FACTOR: f32 = 0.7;
812
const SYSTEM_PROMPT_TOKEN_OVERHEAD: usize = 3_000;
@@ -29,7 +33,10 @@ pub fn get_messages_token_counts(token_counter: &TokenCounter, messages: &[Messa
2933
}
3034

3135
/// Async version of get_messages_token_counts for better performance
32-
pub fn get_messages_token_counts_async(token_counter: &AsyncTokenCounter, messages: &[Message]) -> Vec<usize> {
36+
pub fn get_messages_token_counts_async(
37+
token_counter: &AsyncTokenCounter,
38+
messages: &[Message],
39+
) -> Vec<usize> {
3340
// Calculate current token count of each message, use count_chat_tokens to ensure we
3441
// capture the full content of the message, include ToolRequests and ToolResponses
3542
messages

crates/goose/src/context_mgmt/summarize.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use super::common::{get_messages_token_counts, get_messages_token_counts_async};
22
use crate::message::{Message, MessageContent};
33
use crate::providers::base::Provider;
4-
use crate::token_counter::{TokenCounter, AsyncTokenCounter};
4+
use crate::token_counter::{AsyncTokenCounter, TokenCounter};
55
use anyhow::Result;
66
use mcp_core::Role;
77
use std::sync::Arc;

0 commit comments

Comments
 (0)