lash_core/tool_registry/
state.rs1const PLUGIN_SOURCE_ID: &str = "plugins";
2
3#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
4#[serde(transparent)]
5pub struct ToolSourceHandle {
6 id: String,
7}
8
9impl ToolSourceHandle {
10 pub(crate) fn new(id: impl Into<String>) -> Self {
11 Self { id: id.into() }
12 }
13
14 pub(crate) fn as_str(&self) -> &str {
15 &self.id
16 }
17}
18
19#[derive(Clone, Debug, Serialize, Deserialize)]
20pub struct ToolStateEntry {
21 manifest: ToolManifest,
22 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
27 orphaned: bool,
28}
29
30impl ToolStateEntry {
31 #[cfg(test)]
32 pub(crate) fn new(manifest: ToolManifest) -> Self {
33 Self {
34 manifest,
35 orphaned: false,
36 }
37 }
38
39 pub fn manifest(&self) -> ToolManifest {
43 let mut manifest = self.manifest.clone();
44 if self.orphaned {
45 manifest.availability_override = Some(crate::ToolAvailability::Off);
46 }
47 manifest
48 }
49
50 fn stored_manifest(&self) -> &ToolManifest {
51 &self.manifest
52 }
53
54 pub fn is_orphaned(&self) -> bool {
55 self.orphaned
56 }
57}
58
59#[derive(Clone, Debug, Default)]
60pub struct ToolState {
61 generation: u64,
62 tools: Arc<BTreeMap<ToolId, ToolStateEntry>>,
63}
64
65impl ToolState {
66 pub(crate) fn new(generation: u64, tools: BTreeMap<ToolId, ToolStateEntry>) -> Self {
67 Self {
68 generation,
69 tools: Arc::new(tools),
70 }
71 }
72
73 pub fn generation(&self) -> u64 {
74 self.generation
75 }
76
77 pub fn with_generation(mut self, generation: u64) -> Self {
78 self.generation = generation;
79 self
80 }
81
82 pub fn tool_manifests(&self) -> Vec<ToolManifest> {
83 self.tools.values().map(ToolStateEntry::manifest).collect()
84 }
85
86 pub fn get(&self, id: &ToolId) -> Option<&ToolStateEntry> {
87 self.tools.get(id)
88 }
89
90 pub fn manifest_mut(&mut self, id: &ToolId) -> Option<&mut ToolManifest> {
91 Arc::make_mut(&mut self.tools)
92 .get_mut(id)
93 .map(|entry| &mut entry.manifest)
94 }
95
96 pub fn contains(&self, id: &ToolId) -> bool {
97 self.tools.contains_key(id)
98 }
99
100 pub fn is_empty(&self) -> bool {
101 self.tools.is_empty()
102 }
103
104 pub fn len(&self) -> usize {
105 self.tools.len()
106 }
107
108 pub fn iter(&self) -> impl Iterator<Item = (&ToolId, &ToolStateEntry)> {
109 self.tools.iter()
110 }
111
112 pub fn set_availability(
113 &mut self,
114 id: &ToolId,
115 availability: Option<crate::ToolAvailability>,
116 ) -> Result<(), ReconfigureError> {
117 let Some(entry) = Arc::make_mut(&mut self.tools).get_mut(id) else {
118 return Err(ReconfigureError::Validation(format!(
119 "unknown tool id `{id}`"
120 )));
121 };
122 entry.manifest.availability_override = availability;
123 Ok(())
124 }
125
126 pub fn retain(&mut self, mut keep: impl FnMut(&ToolId, &ToolStateEntry) -> bool) {
127 Arc::make_mut(&mut self.tools).retain(|id, entry| keep(id, entry));
128 }
129
130 pub fn remove(&mut self, id: &ToolId) -> Option<ToolStateEntry> {
131 Arc::make_mut(&mut self.tools).remove(id)
132 }
133
134 pub(crate) fn entries(&self) -> &BTreeMap<ToolId, ToolStateEntry> {
135 self.tools.as_ref()
136 }
137}
138
139impl Serialize for ToolState {
140 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
141 where
142 S: serde::Serializer,
143 {
144 #[derive(Serialize)]
145 struct ToolStateRef<'a> {
146 generation: u64,
147 tools: &'a BTreeMap<ToolId, ToolStateEntry>,
148 }
149
150 ToolStateRef {
151 generation: self.generation,
152 tools: self.tools.as_ref(),
153 }
154 .serialize(serializer)
155 }
156}
157
158impl<'de> Deserialize<'de> for ToolState {
159 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
160 where
161 D: serde::Deserializer<'de>,
162 {
163 #[derive(Deserialize)]
164 struct ToolStateOwned {
165 generation: u64,
166 tools: BTreeMap<ToolId, ToolStateEntry>,
167 }
168
169 let owned = ToolStateOwned::deserialize(deserializer)?;
170 Ok(Self {
171 generation: owned.generation,
172 tools: Arc::new(owned.tools),
173 })
174 }
175}
176
177#[async_trait::async_trait]
178pub(crate) trait ToolSourceExecutor: Send + Sync + 'static {
179 fn id(&self) -> &str;
180 fn advertised_tools(&self) -> Vec<ToolManifest>;
181 fn resolve_manifest(&self, name: &str) -> Option<ToolManifest> {
182 self.advertised_tools()
183 .into_iter()
184 .find(|manifest| manifest.name == name)
185 }
186 fn resolve_manifest_by_id(&self, id: &ToolId) -> Option<ToolManifest> {
187 self.advertised_tools()
188 .into_iter()
189 .find(|manifest| manifest.id == *id)
190 }
191 fn resolve_contract(&self, name: &str) -> Option<Arc<ToolContract>>;
192 fn resolve_contract_by_id(&self, id: &ToolId) -> Option<Arc<ToolContract>> {
193 let manifest = self.resolve_manifest_by_id(id)?;
194 self.resolve_contract(&manifest.name)
195 }
196 async fn prepare_tool_call(
197 &self,
198 call: ToolPrepareCall<'_>,
199 ) -> Result<PreparedToolCall, ToolResult> {
200 Ok(PreparedToolCall::identity(call.tool_id, call.pending))
201 }
202 async fn execute(
203 &self,
204 tool: &str,
205 args: &serde_json::Value,
206 context: &ToolContext<'_>,
207 progress: Option<&ProgressSender>,
208 ) -> ToolResult;
209}