test(agent): Add unit tests for agent-core and fix clippy warnings
This commit is contained in:
@@ -159,10 +159,10 @@ impl Compactor {
|
||||
let mut summary = String::new();
|
||||
use futures_util::StreamExt;
|
||||
while let Some(chunk_result) = stream.next().await {
|
||||
if let Ok(chunk) = chunk_result {
|
||||
if let Some(content) = &chunk.content {
|
||||
summary.push_str(content);
|
||||
}
|
||||
if let Ok(chunk) = chunk_result
|
||||
&& let Some(content) = &chunk.content
|
||||
{
|
||||
summary.push_str(content);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -195,14 +195,14 @@ mod tests {
|
||||
|
||||
// Small message list shouldn't compact
|
||||
let small_messages: Vec<ChatMessage> = (0..10)
|
||||
.map(|i| ChatMessage::user(&format!("Message {}", i)))
|
||||
.map(|i| ChatMessage::user(format!("Message {}", i)))
|
||||
.collect();
|
||||
assert!(!counter.should_compact(&small_messages));
|
||||
|
||||
// Large message list should compact
|
||||
// Need ~162,000 tokens = ~648,000 chars (at 4 chars per token)
|
||||
let large_content = "x".repeat(700_000);
|
||||
let large_messages = vec![ChatMessage::user(&large_content)];
|
||||
let large_messages = vec![ChatMessage::user(large_content)];
|
||||
assert!(counter.should_compact(&large_messages));
|
||||
}
|
||||
|
||||
@@ -211,7 +211,7 @@ mod tests {
|
||||
let compactor = Compactor::new();
|
||||
|
||||
let small: Vec<ChatMessage> = (0..5)
|
||||
.map(|i| ChatMessage::user(&format!("Short message {}", i)))
|
||||
.map(|i| ChatMessage::user(format!("Short message {}", i)))
|
||||
.collect();
|
||||
assert!(!compactor.needs_compaction(&small));
|
||||
}
|
||||
|
||||
@@ -928,7 +928,7 @@ pub async fn run_agent_loop<P: LlmProvider>(
|
||||
let new_args = current_args + &args_delta;
|
||||
// Try to parse as JSON, but keep as string if incomplete
|
||||
tool_call.function.arguments = serde_json::from_str(&new_args)
|
||||
.unwrap_or_else(|_| Value::String(new_args));
|
||||
.unwrap_or(Value::String(new_args));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1128,3 +1128,65 @@ pub async fn run_agent_loop_streaming<P: LlmProvider>(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use llm_core::ToolCallDelta;
|
||||
|
||||
#[test]
|
||||
fn test_tool_calls_builder() {
|
||||
let mut builder = ToolCallsBuilder::new();
|
||||
|
||||
// Add first tool call deltas
|
||||
builder.add_deltas(&[
|
||||
ToolCallDelta {
|
||||
index: 0,
|
||||
id: Some("call_1".to_string()),
|
||||
function_name: Some("read".to_string()),
|
||||
arguments_delta: Some("{\"path\":".to_string()),
|
||||
}
|
||||
]);
|
||||
|
||||
// Add second tool call deltas
|
||||
builder.add_deltas(&[
|
||||
ToolCallDelta {
|
||||
index: 1,
|
||||
id: Some("call_2".to_string()),
|
||||
function_name: Some("write".to_string()),
|
||||
arguments_delta: Some("{\"path\":\"test.txt\"".to_string()),
|
||||
}
|
||||
]);
|
||||
|
||||
// Add more deltas for first tool call
|
||||
builder.add_deltas(&[
|
||||
ToolCallDelta {
|
||||
index: 0,
|
||||
id: None,
|
||||
function_name: None,
|
||||
arguments_delta: Some("\"lib.rs\"}".to_string()),
|
||||
}
|
||||
]);
|
||||
|
||||
// Add more deltas for second tool call
|
||||
builder.add_deltas(&[
|
||||
ToolCallDelta {
|
||||
index: 1,
|
||||
id: None,
|
||||
function_name: None,
|
||||
arguments_delta: Some(",\"content\":\"hello\"}".to_string()),
|
||||
}
|
||||
]);
|
||||
|
||||
let calls = builder.build();
|
||||
assert_eq!(calls.len(), 2);
|
||||
|
||||
assert_eq!(calls[0].id, "call_1");
|
||||
assert_eq!(calls[0].function.name, "read");
|
||||
assert_eq!(calls[0].function.arguments, json!({"path": "lib.rs"}));
|
||||
|
||||
assert_eq!(calls[1].id, "call_2");
|
||||
assert_eq!(calls[1].function.name, "write");
|
||||
assert_eq!(calls[1].function.arguments, json!({"path": "test.txt", "content": "hello"}));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,10 +183,10 @@ impl Checkpoint {
|
||||
for entry in fs::read_dir(checkpoint_dir)? {
|
||||
let entry = entry?;
|
||||
let path = entry.path();
|
||||
if path.extension().and_then(|s| s.to_str()) == Some("json") {
|
||||
if let Some(stem) = path.file_stem().and_then(|s| s.to_str()) {
|
||||
checkpoints.push(stem.to_string());
|
||||
}
|
||||
if path.extension().and_then(|s| s.to_str()) == Some("json")
|
||||
&& let Some(stem) = path.file_stem().and_then(|s| s.to_str())
|
||||
{
|
||||
checkpoints.push(stem.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -47,27 +47,27 @@ impl SystemPromptBuilder {
|
||||
pub fn with_project_instructions(mut self, project_root: &Path) -> Self {
|
||||
// Try CLAUDE.md first (Claude Code compatibility)
|
||||
let claude_md = project_root.join("CLAUDE.md");
|
||||
if claude_md.exists() {
|
||||
if let Ok(content) = std::fs::read_to_string(&claude_md) {
|
||||
self.sections.push(PromptSection {
|
||||
name: "project".to_string(),
|
||||
content: format!("# Project Instructions\n\n{}", content),
|
||||
priority: 20,
|
||||
});
|
||||
return self;
|
||||
}
|
||||
if claude_md.exists()
|
||||
&& let Ok(content) = std::fs::read_to_string(&claude_md)
|
||||
{
|
||||
self.sections.push(PromptSection {
|
||||
name: "project".to_string(),
|
||||
content: format!("# Project Instructions\n\n{}", content),
|
||||
priority: 20,
|
||||
});
|
||||
return self;
|
||||
}
|
||||
|
||||
// Fallback to .owlen.md
|
||||
let owlen_md = project_root.join(".owlen.md");
|
||||
if owlen_md.exists() {
|
||||
if let Ok(content) = std::fs::read_to_string(&owlen_md) {
|
||||
self.sections.push(PromptSection {
|
||||
name: "project".to_string(),
|
||||
content: format!("# Project Instructions\n\n{}", content),
|
||||
priority: 20,
|
||||
});
|
||||
}
|
||||
if owlen_md.exists()
|
||||
&& let Ok(content) = std::fs::read_to_string(&owlen_md)
|
||||
{
|
||||
self.sections.push(PromptSection {
|
||||
name: "project".to_string(),
|
||||
content: format!("# Project Instructions\n\n{}", content),
|
||||
priority: 20,
|
||||
});
|
||||
}
|
||||
|
||||
self
|
||||
|
||||
Reference in New Issue
Block a user