1use object_store::path::DELIMITER;
17use std::{future::Future, pin::Pin};
18
19pub mod agent;
20pub mod context;
21pub mod http;
22pub mod json;
23pub mod model;
24pub mod tool;
25
26pub use agent::*;
27pub use context::*;
28pub use http::*;
29pub use json::*;
30pub use model::*;
31pub use tool::*;
32
33pub type BoxError = Box<dyn std::error::Error + Send + Sync>;
36
37pub type BoxPinFut<T> = Pin<Box<dyn Future<Output = T> + Send>>;
39
40pub fn path_lowercase(path: &Path) -> Path {
42 let mut path = path.to_string();
43 path.make_ascii_lowercase();
44 path.into()
45}
46
47pub fn path_join(a: &Path, b: &Path) -> Path {
52 let mut path = if a.is_root() {
53 b.to_string()
54 } else if b.is_root() {
55 a.to_string()
56 } else {
57 format!("{}{}{}", a, DELIMITER, b)
58 };
59 path.make_ascii_lowercase();
60 path.into()
61}
62
63pub fn validate_path_part(part: &str) -> Result<(), BoxError> {
68 if part.is_empty() || part.contains(DELIMITER) || Path::from(part).as_ref() != part {
69 return Err(format!("invalid path part: {}", part).into());
70 }
71
72 Ok(())
73}
74
75pub fn validate_function_name(name: &str) -> Result<(), BoxError> {
83 if name.is_empty() {
84 return Err("empty string".into());
85 }
86
87 if name.len() > 64 {
88 return Err("string length exceeds the limit 64".into());
89 }
90
91 let mut iter = name.chars();
92 if !matches!(iter.next(), Some('a'..='z')) {
93 return Err("name must start with a lowercase letter".into());
94 }
95
96 for c in iter {
97 if !matches!(c, 'a'..='z' | '0'..='9' | '_' ) {
98 return Err(format!("invalid character: {}", c).into());
99 }
100 }
101 Ok(())
102}
103
104#[cfg(test)]
105mod tests {
106 use super::*;
107
108 #[test]
109 fn test_path_lowercase() {
110 let a = Path::from("a/Foo");
111 assert_eq!(path_lowercase(&a).as_ref(), "a/foo");
112 }
113
114 #[test]
115 fn test_validate_path_part() {
116 assert!(validate_path_part("foo").is_ok());
117 assert!(validate_path_part("fOO").is_ok());
118 assert!(validate_path_part("").is_err());
119 assert!(validate_path_part("foo/").is_err());
120 assert!(validate_path_part("/foo").is_err());
121 assert!(validate_path_part("foo/bar").is_err());
122 assert!(validate_path_part("foo/bar/").is_err());
123 }
124}