- 1
//! Retired tool registry. - 2
//! - 3
//! When a tool is removed from the agent's callable interface, its name - 4
//! enters `RETIRED_TOOLS` so that plugin skill descriptions, prompt text, - 5
//! or cached session data referencing it can be detected and cleaned up. - 6
//! - 7
//! A retired tool name may appear in: - 8
//! - A skill `SKILL.md` body/description that still instructs the model to - 9
//! call it (the `python_eval` / `react_preview` hallucination class). - 10
//! - A stale `[plugins] network_allow` entry in `.vak/config.toml`. - 11
//! - A cached `TurnCapabilitiesBound` entry in a session ledger. - 12
//! - 13
//! The cleanup pass in `vak_core::seed` and `PluginStore::retired_plugins` - 14
//! consults this list. Each entry carries the last version in which the - 15
//! tool was available and the replacement instruction for migration. - 16
- 17
/// A single retired tool reference with migration context. - 18
#[derive(Debug, Clone, PartialEq, Eq)] - 19
pub struct RetiredTool { - 20
/// The exact tool name the model might try to call. - 21
pub name: &'static str, - 22
/// The AGENTS.md version when the tool was removed. - 23
pub retired_in: &'static str, - 24
/// Replacement: what the model should use instead. - 25
pub replacement: &'static str, - 26
} - 27
- 28
/// The compiled-in list of retired tool names, ordered by retirement date. - 29
pub const RETIRED_TOOLS: &[RetiredTool] = &[ - 30
RetiredTool { - 31
name: "python_eval", - 32
retired_in: "3.0.21", - 33
replacement: "bash — run Python via the `bash` tool (e.g. `python3 script.py`)", - 34
}, - 35
RetiredTool { - 36
name: "react_preview", - 37
retired_in: "3.0.21", - 38
replacement: "bash — run React/preview tooling via the `bash` tool", - 39
}, - 40
]; - 41
- 42
/// Returns `true` if `name` matches a retired tool (case-insensitive). - 43
pub fn is_retired(name: &str) -> bool { - 44
RETIRED_TOOLS - 45
.iter() - 46
.any(|tool| tool.name.eq_ignore_ascii_case(name)) - 47
} - 48
- 49
/// Returns the replacement instruction for `name`, if it is retired. - 50
pub fn replacement_for(name: &str) -> Option<&'static str> { - 51
RETIRED_TOOLS - 52
.iter() - 53
.find(|tool| tool.name.eq_ignore_ascii_case(name)) - 54
.map(|tool| tool.replacement) - 55
} - 56
- 57
/// Returns all retired tool names as a `Vec<&str>`. - 58
pub fn retired_names() -> Vec<&'static str> { - 59
RETIRED_TOOLS.iter().map(|t| t.name).collect() - 60
} - 61
- 62
#[cfg(test)] - 63
mod tests { - 64
use super::*; - 65
- 66
#[test] - 67
fn python_eval_is_retired() { - 68
assert!(is_retired("python_eval")); - 69
assert!(is_retired("python_eval")); - 70
assert!(!is_retired("bash")); - 71
} - 72
- 73
#[test] - 74
fn react_preview_is_retired() { - 75
assert!(is_retired("react_preview")); - 76
assert!(!is_retired("read")); - 77
} - 78
- 79
#[test] - 80
fn replacement_is_not_empty() { - 81
for tool in RETIRED_TOOLS { - 82
assert!( - 83
!tool.replacement.is_empty(), - 84
"{} must have a non-empty replacement", - 85
tool.name - 86
); - 87
} - 88
} - 89
- 90
#[test] - 91
fn no_duplicate_retired_names() { - 92
let names: Vec<_> = RETIRED_TOOLS.iter().map(|t| t.name).collect(); - 93
let unique: std::collections::HashSet<_> = names.iter().collect(); - 94
assert_eq!(names.len(), unique.len(), "duplicate retired tool names"); - 95
} - 96
} - 97
Indexing the workspace…
Vakyartha documentation is discovering safe artifacts, anchors, and source references.