Skip to main content

synaps_cli/extensions/
capability.rs

1//! Unified capability snapshot for extensions.
2//!
3//! Aggregates hook subscriptions, extension-provided tools, and registered
4//! providers into a single per-extension summary. Plugin-declared
5//! capability kinds plug in here without core enumeration.
6
7use crate::extensions::providers::RegisteredProviderSummary;
8use crate::extensions::runtime::ExtensionHealth;
9
10#[derive(Debug, Clone, PartialEq, Eq)]
11pub struct ExtensionCapabilitySnapshot {
12    pub id: String,
13    pub health: ExtensionHealth,
14    pub restart_count: usize,
15    pub hooks: Vec<HookCapabilityEntry>,
16    pub tools: Vec<ToolCapabilityEntry>,
17    pub providers: Vec<RegisteredProviderSummary>,
18    /// Plugin-declared capability entries. Empty when none are advertised.
19    pub future: Vec<FutureCapabilityEntry>,
20}
21
22#[derive(Debug, Clone, PartialEq, Eq)]
23pub struct HookCapabilityEntry {
24    /// Hook kind name, e.g. "before_tool_call".
25    pub kind: String,
26    /// Optional tool filter, if the subscription is bound to a specific tool name.
27    pub tool_filter: Option<String>,
28}
29
30#[derive(Debug, Clone, PartialEq, Eq)]
31pub struct ToolCapabilityEntry {
32    /// Fully namespaced tool name.
33    pub name: String,
34}
35
36#[derive(Debug, Clone, PartialEq, Eq)]
37pub struct FutureCapabilityEntry {
38    pub kind: String, // free-form capability kind declared by the plugin
39    pub name: String,
40}
41
42#[cfg(test)]
43mod tests {
44    use super::*;
45
46    #[test]
47    fn snapshot_literal_round_trips_equality() {
48        let snap = ExtensionCapabilitySnapshot {
49            id: "demo".to_string(),
50            health: ExtensionHealth::Running,
51            restart_count: 0,
52            hooks: vec![HookCapabilityEntry {
53                kind: "before_tool_call".to_string(),
54                tool_filter: Some("bash".to_string()),
55            }],
56            tools: vec![ToolCapabilityEntry {
57                name: "demo:hello".to_string(),
58            }],
59            providers: vec![],
60            future: vec![FutureCapabilityEntry {
61                kind: "memory".to_string(),
62                name: "shortterm".to_string(),
63            }],
64        };
65
66        let same = snap.clone();
67        assert_eq!(snap, same);
68        assert_eq!(snap.hooks[0].tool_filter.as_deref(), Some("bash"));
69        assert_eq!(snap.tools[0].name, "demo:hello");
70        assert_eq!(snap.future[0].kind, "memory");
71    }
72}