Skip to content

Commit e54e5fd

Browse files
committed
feat: add tool name prefix config
Signed-off-by: Tuan Anh Tran <[email protected]>
1 parent 65f3b83 commit e54e5fd

File tree

3 files changed

+88
-5
lines changed

3 files changed

+88
-5
lines changed

RUNTIME_CONFIG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ The configuration is structured as follows:
1313
- **allowed_paths** (`array[string]`, optional): List of allowed file system paths.
1414
- **env_vars** (`object`, optional): Key-value pairs of environment variables for the plugin.
1515
- **memory_limit** (`string`, optional): Memory limit for the plugin (e.g., `"512Mi"`).
16+
- **tool_name_prefix** (`string`, optional): Optional prefix for tool names. Can be use to prevent tool name collision.
1617

1718
## Example (YAML)
1819

@@ -48,7 +49,8 @@ plugins:
4849
"allowed_hosts": ["1.1.1.1"],
4950
"skip_tools": ["debug"],
5051
"env_vars": {"FOO": "bar"},
51-
"memory_limit": "512Mi"
52+
"memory_limit": "512Mi",
53+
"tool_name_prefix": "foo_"
5254
}
5355
}
5456
]

src/config.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ pub struct RuntimeConfig {
2323
pub allowed_paths: Option<Vec<String>>,
2424
pub env_vars: Option<HashMap<String, String>>,
2525
pub memory_limit: Option<String>,
26+
pub tool_name_prefix: Option<String>,
2627
}
2728

2829
pub async fn load_config(path: &Path) -> Result<Config> {

src/plugins.rs

Lines changed: 84 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -200,15 +200,72 @@ impl ServerHandler for PluginService {
200200
let tool_cache = self.tool_plugin_map.read().await;
201201

202202
let tool_name = request.name.clone();
203+
let tool_name_str = tool_name.to_string();
204+
205+
// Find the plugin name and strip the prefix if needed
206+
let mut original_name = tool_name_str.clone();
207+
let mut plugin_name_for_tool = None;
208+
209+
// First try to find the tool directly in the cache
210+
if let Some(plugin_name) = tool_cache.get(&tool_name_str) {
211+
plugin_name_for_tool = Some(plugin_name.clone());
212+
213+
// Check if this tool has a prefix that needs to be stripped
214+
for plugin_cfg in &self.config.plugins {
215+
if let Some(rt_config) = &plugin_cfg.runtime_config {
216+
if let Some(tool_name_prefix) = &rt_config.tool_name_prefix {
217+
if tool_name_str.starts_with(tool_name_prefix) {
218+
// Strip the prefix to get the original tool name
219+
original_name = tool_name_str[tool_name_prefix.len()..].to_string();
220+
log::info!(
221+
"Found tool with prefix, stripping for internal call: {} -> {}",
222+
tool_name_str,
223+
original_name
224+
);
225+
break;
226+
}
227+
}
228+
}
229+
}
230+
} else {
231+
// If not found directly, check if it has a prefix that needs to be stripped
232+
for plugin_cfg in &self.config.plugins {
233+
if let Some(rt_config) = &plugin_cfg.runtime_config {
234+
if let Some(tool_name_prefix) = &rt_config.tool_name_prefix {
235+
if tool_name_str.starts_with(tool_name_prefix) {
236+
// Strip the prefix to get the original tool name
237+
original_name = tool_name_str[tool_name_prefix.len()..].to_string();
238+
log::info!(
239+
"Stripping prefix from tool: {} -> {}",
240+
tool_name_str,
241+
original_name
242+
);
243+
244+
// Check if the original tool name is in the cache
245+
if let Some(plugin_name) = tool_cache.get(&original_name) {
246+
plugin_name_for_tool = Some(plugin_name.clone());
247+
break;
248+
}
249+
}
250+
}
251+
}
252+
}
253+
}
254+
255+
// Create a modified request with the original tool name
256+
let mut modified_request = request.clone();
257+
// Convert the String to Cow<'static, str> using into()
258+
modified_request.name = std::borrow::Cow::Owned(original_name);
259+
203260
let call_payload = json!({
204-
"params": request,
261+
"params": modified_request,
205262
});
206263
let json_string =
207264
serde_json::to_string(&call_payload).expect("Failed to serialize request");
208265

209266
// Check if the tool exists in the cache
210-
if let Some(plugin_name) = tool_cache.get(&tool_name.to_string()) {
211-
if let Some(plugin_arc) = plugins.get(plugin_name) {
267+
if let Some(plugin_name) = plugin_name_for_tool {
268+
if let Some(plugin_arc) = plugins.get(&plugin_name) {
212269
let plugin_clone = Arc::clone(plugin_arc);
213270
let plugin_name_clone = plugin_name.clone();
214271

@@ -277,14 +334,37 @@ impl ServerHandler for PluginService {
277334
.as_ref()
278335
.and_then(|rc| rc.skip_tools.clone())
279336
.unwrap_or_default();
280-
for tool in parsed.tools {
337+
for mut tool in parsed.tools {
281338
if skip_tools.iter().any(|s| s == tool.name.as_ref() as &str) {
282339
log::info!(
283340
"Skipping tool {} as requested in skip_tools",
284341
tool.name
285342
);
286343
continue;
287344
}
345+
// If tool_name_prefix is set, append it to the tool name
346+
let original_name = tool.name.to_string();
347+
if let Some(runtime_cfg) = &plugin_cfg.runtime_config {
348+
if let Some(tool_name_prefix) = &runtime_cfg.tool_name_prefix {
349+
let prefixed_name =
350+
format!("{}{}", tool_name_prefix, original_name);
351+
log::info!(
352+
"Adding prefix to tool: {} -> {}",
353+
original_name,
354+
prefixed_name
355+
);
356+
357+
// Store both the original and prefixed tool names in the cache
358+
// This ensures we can find the tool by either name
359+
tool_cache
360+
.insert(original_name.clone(), plugin_cfg.name.clone());
361+
362+
// Update the tool name with the prefix
363+
tool.name = std::borrow::Cow::Owned(prefixed_name);
364+
}
365+
}
366+
367+
// Store the tool name (which might be prefixed now) -> plugin mapping
288368
tool_cache.insert(tool.name.to_string(), plugin_cfg.name.clone());
289369
payload.tools.push(tool);
290370
}

0 commit comments

Comments
 (0)