refactoring

This commit is contained in:
pavel 2026-02-11 01:29:23 +01:00
commit 13e17770ca
12 changed files with 634 additions and 598 deletions

View file

@ -1,166 +0,0 @@
use chrono::Utc;
use std::time::{Duration, Instant};
use crate::api::{ChatRequest, ChatResponse, Message, Tool};
use crate::tools;
pub struct Agent {
client: reqwest::Client,
url: String,
zen_api_key: Option<String>,
tavily_api_key: Option<String>,
messages: Vec<Message>,
tools: Option<Vec<Tool>>,
logs: String,
answer: Option<String>,
}
impl Agent {
pub fn new(
zen_api_key: Option<String>,
tavily_api_key: Option<String>,
initial_message: String,
) -> Result<Self, Box<dyn std::error::Error>> {
let intro = format!(
"You are an autonomous agent. You have access to tools that can help
you achieve your goals. Use them wisely. The user is unable to respond to you
so do not ask for clarification and use the
answer tool once you to give your final answer. current date is {}",
Utc::now().format("%B %d, %Y %H:%M:%S UTC").to_string()
);
let messages = vec![
Message {
role: "system".to_string(),
content: Some(intro),
tool_calls: None,
tool_call_id: None,
},
Message {
role: "user".to_string(),
content: Some(initial_message),
tool_calls: None,
tool_call_id: None,
},
];
let tools = Some(tools::get_tools());
let client = reqwest::Client::builder()
.timeout(std::time::Duration::from_secs(60))
.build()?;
Ok(Self {
client,
url: "https://opencode.ai/zen/v1/chat/completions".to_string(),
zen_api_key,
tavily_api_key,
messages,
tools,
logs: String::new(),
answer: None,
})
}
fn log(&mut self, message: &str) {
self.logs.push_str(message);
self.logs.push('\n');
}
pub async fn run(
&mut self,
config: &crate::config::Config,
) -> Result<(String, Option<String>), Box<dyn std::error::Error>> {
let mut finished = false;
let start_time = Instant::now();
let max_duration = Duration::from_secs(config.agent_max_duration_secs);
let max_turns = config.agent_max_turns;
let mut turns = 0;
while !finished {
if start_time.elapsed() > max_duration {
return Err("Agent run timed out".into());
}
if turns >= max_turns {
return Err("Agent run exceeded max turns".into());
}
turns += 1;
let request = ChatRequest {
model: "kimi-k2.5".to_string(),
messages: self.messages.clone(),
tools: self.tools.clone(),
};
self.log(&format!(
"--- Sending request to Zen API (Role: {}) ---",
self.messages.last().unwrap().role
));
let mut request_builder = self.client.post(&self.url).json(&request);
if let Some(key) = &self.zen_api_key {
request_builder =
request_builder.header("Authorization", format!("Bearer {}", key));
}
let response = request_builder.send().await?;
if !response.status().is_success() {
let status = response.status();
let error_text = response.text().await?;
self.log(&format!("Error: API request failed with status {}", status));
self.log(&format!("Error details: {}", error_text));
return Err(format!("API request failed: {}", status).into());
}
let chat_response: ChatResponse = response.json().await?;
let assistant_message = chat_response
.choices
.get(0)
.ok_or("Missing assistant response")?
.message
.clone();
self.messages.push(assistant_message.clone());
if let Some(content) = &assistant_message.content {
if !content.is_empty() {
self.log(&format!("\nAssistant response:\n{}\n", content));
}
}
if let Some(tool_calls) = assistant_message.tool_calls {
for tool_call in tool_calls {
let (tool_message, written, tool_answer) =
tools::handle_tool_call(&tool_call, &self.tavily_api_key).await?;
if let Some(ans) = tool_answer {
self.answer = Some(ans);
}
if let Some(content) = &tool_message.content {
self.log(&format!(
"Tool result ({}): {}",
tool_call.function.name, content
));
}
self.messages.push(tool_message);
if written {
finished = true;
}
}
// Continue the loop to send tool results back
continue;
}
// No tool calls from assistant, but we only exit if the task was finished
if !finished {
self.log("--- Assistant didn't finish yet. Waiting for next turn... ---");
}
}
Ok((self.logs.clone(), self.answer.clone()))
}
}