first commit

This commit is contained in:
aiyezi committed 2026-11-05 17:33:18 +08:00
commit 91b44fcc16
27 files changed
+4104

No files matched your search

+11
View File
@@ -0,0 +1,11 @@
[package]
name = "agent-tools"
version = "0.1.0"
edition = "2024"
[dependencies]
serde = { workspace = true }
serde_json = { workspace = true }
agent-core = { path = "../agent-core" }
async-trait = { workspace = true }
jiff = "0.2.37"
+2
View File
@@ -0,0 +1,2 @@
mod read;
pub use read::ReadFileTool;
+99
View File
@@ -0,0 +1,99 @@
use std::{
fmt::Write,
fs::File,
io::{BufRead, BufReader},
};
use agent_core::{AgentError, Tool};
use async_trait::async_trait;
use serde::Deserialize;
pub struct ReadFileTool;
#[derive(Deserialize)]
struct ToolArgs {
pub path: String,
pub range: Option<(usize, usize)>,
}
#[async_trait]
impl Tool for ReadFileTool {
fn name(&self) -> &str {
"read_file"
}
fn description(&self) -> &str {
"Reads the contents of a file at the specified path."
}
fn parameters(&self) -> serde_json::Value {
serde_json::json!({
"type": "object",
"properties": {
"path": {
"type": "string",
"description": "The path to the file to read."
},
"range": {
"type": "array",
"description": "Optional line range [start, count], Number of lines to read. For example, start=100, count=50 reads lines 100 to 149 (inclusive)",
"items": {
"type": "integer"
},
"maxItems": 2,
"minItems": 2
}
},
"required": ["path"]
})
}
async fn run(&self, arguments: &str) -> Result<String, AgentError> {
let args: ToolArgs = serde_json::from_str(arguments)
.map_err(|e| AgentError::Provider(format!("Invalid arguments {e}")))?;
let file =
File::open(args.path).map_err(|e| AgentError::Provider(format!("Invalid path {e}")))?;
read_line(args.range, file)
}
}
fn read_line(range: Option<(usize, usize)>, file: File) -> Result<String, AgentError> {
let reader = BufReader::new(file);
let mut ans = String::new();
match range {
Some((start, count)) => {
if start == 0 {
return Err(AgentError::Provider(format!(
"Invalid arguments: start must be >= 1, got {}",
start
)));
}
if count > 200 {
return Err(AgentError::Provider(format!(
"Invalid arguments: count must be <= 200, got {}",
count
)));
}
for (i, line) in reader.lines().skip(start - 1).take(count).enumerate() {
let line =
line.map_err(|e| AgentError::Provider(format!("failed to read file: {}", e)))?;
writeln!(ans, "[{}]: {}", start + i, line)?
}
}
None => {
// 明确上限,避免模型无界读取
const MAX_LINES: usize = 1000;
for (i, line) in reader.lines().take(MAX_LINES).enumerate() {
let line =
line.map_err(|e| AgentError::Provider(format!("failed to read file: {}", e)))?;
writeln!(ans, "[{}]: {}", i + 1, line)?
}
}
}
Ok(ans)
}
+19
View File
@@ -0,0 +1,19 @@
mod fs;
mod time;
pub use fs::ReadFileTool;
pub use time::CurrentTimeTool;
pub fn add(left: u64, right: u64) -> u64 {
left + right
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
let result = add(2, 2);
assert_eq!(result, 4);
}
}
+60
View File
@@ -0,0 +1,60 @@
use agent_core::{AgentError, Tool};
use async_trait::async_trait;
use jiff::Zoned;
use serde::Deserialize;
pub struct CurrentTimeTool;
#[derive(Deserialize, Default)]
pub struct TimeArgs {
#[serde(default)]
timezone: Option<String>,
}
#[async_trait]
impl Tool for CurrentTimeTool {
fn name(&self) -> &str {
"get_current_time"
}
fn description(&self) -> &str {
"get system now time"
}
fn parameters(&self) -> serde_json::Value {
serde_json::json!({
"type": "object",
"properties": {
"timezone": {
"type": "string",
"description": "Optional IANA timezone name (e.g., 'Asia/Shanghai', 'America/New_York', 'UTC'). If not provided, the local system timezone is used."
}
}
})
}
async fn run(&self, arguments: &str) -> Result<String, AgentError> {
let args: TimeArgs = if arguments.trim().is_empty() {
TimeArgs::default()
} else {
serde_json::from_str(arguments)
.map_err(|e| AgentError::Provider(format!("invaild argments {e}")))?
};
let now = Zoned::now();
let target_time = match args.timezone.as_deref() {
Some(tz) if !tz.trim().is_empty() => now
.in_tz(tz)
.map_err(|e| AgentError::Provider(format!("invalid timezone '{tz}': {e}")))?,
_ => now,
};
let formatted = format!(
"{} [{}]",
target_time.strftime("%Y-%m-%d %H:%M:%S %A"),
target_time.time_zone().iana_name().unwrap_or("Unknown")
);
Ok(formatted)
}
}