agent_sdk/
primitive_tools.rs1mod bash;
14mod edit;
15mod glob;
16mod grep;
17mod read;
18mod write;
19
20pub use bash::BashTool;
21pub use edit::EditTool;
22pub use glob::GlobTool;
23pub use grep::GrepTool;
24pub use read::ReadTool;
25pub use write::WriteTool;
26
27use crate::{AgentCapabilities, Environment};
28use serde::Deserialize;
29use serde::de::{self, Deserializer};
30use std::fmt::Display;
31use std::str::FromStr;
32use std::sync::Arc;
33
34pub struct PrimitiveToolContext<E: Environment> {
36 pub environment: Arc<E>,
37 pub capabilities: AgentCapabilities,
38}
39
40impl<E: Environment> PrimitiveToolContext<E> {
41 #[must_use]
42 pub const fn new(environment: Arc<E>, capabilities: AgentCapabilities) -> Self {
43 Self {
44 environment,
45 capabilities,
46 }
47 }
48}
49
50impl<E: Environment> Clone for PrimitiveToolContext<E> {
51 fn clone(&self) -> Self {
52 Self {
53 environment: Arc::clone(&self.environment),
54 capabilities: self.capabilities.clone(),
55 }
56 }
57}
58
59#[derive(Deserialize)]
60#[serde(untagged)]
61enum StringOrU64 {
62 Number(u64),
63 String(String),
64}
65
66#[derive(Deserialize)]
67#[serde(untagged)]
68enum StringOrUsize {
69 Number(usize),
70 String(String),
71}
72
73fn parse_numeric_string<T>(value: &str) -> Result<T, String>
74where
75 T: FromStr,
76 T::Err: Display,
77{
78 value
79 .trim()
80 .parse::<T>()
81 .map_err(|error| format!("invalid numeric string '{value}': {error}"))
82}
83
84pub(super) fn deserialize_optional_u64_from_string_or_int<'de, D>(
85 deserializer: D,
86) -> Result<Option<u64>, D::Error>
87where
88 D: Deserializer<'de>,
89{
90 match Option::<StringOrU64>::deserialize(deserializer)? {
91 None => Ok(None),
92 Some(StringOrU64::Number(value)) => Ok(Some(value)),
93 Some(StringOrU64::String(value)) => parse_numeric_string(&value)
94 .map(Some)
95 .map_err(de::Error::custom),
96 }
97}
98
99pub(super) fn deserialize_optional_usize_from_string_or_int<'de, D>(
100 deserializer: D,
101) -> Result<Option<usize>, D::Error>
102where
103 D: Deserializer<'de>,
104{
105 match Option::<StringOrUsize>::deserialize(deserializer)? {
106 None => Ok(None),
107 Some(StringOrUsize::Number(value)) => Ok(Some(value)),
108 Some(StringOrUsize::String(value)) => parse_numeric_string(&value)
109 .map(Some)
110 .map_err(de::Error::custom),
111 }
112}