Skip to main content

rpi_cli/
extension_api.rs

1//! Stable capability contracts shared by native and Node extension backends.
2//!
3//! The CLI consumes extension metadata through these small contracts instead
4//! of depending on the implementation (cdylib or Node/RPC). New backends can
5//! opt into capabilities without changing the TUI or agent orchestration.
6
7use std::collections::BTreeSet;
8
9pub const EXTENSION_API_VERSION: u32 = 1;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
12pub enum ExtensionCapability {
13    Tools,
14    Commands,
15    Resources,
16    UiNotify,
17    UiEditor,
18    UiCustom,
19    UiSelect,
20    UiConfirm,
21    UiInput,
22    UiEditorDialog,
23    Session,
24    Models,
25    Events,
26    Providers,
27    ProviderCalls,
28    Renderers,
29    RuntimeActions,
30}
31
32impl ExtensionCapability {
33    pub const fn as_str(self) -> &'static str {
34        match self {
35            Self::Tools => "tools",
36            Self::Commands => "commands",
37            Self::Resources => "resources",
38            Self::UiNotify => "ui.notify",
39            Self::UiEditor => "ui.editor",
40            Self::UiCustom => "ui.custom",
41            Self::UiSelect => "ui.select",
42            Self::UiConfirm => "ui.confirm",
43            Self::UiInput => "ui.input",
44            Self::UiEditorDialog => "ui.editor_dialog",
45            Self::Session => "session",
46            Self::Models => "models",
47            Self::Events => "events",
48            Self::Providers => "providers",
49            Self::ProviderCalls => "provider_calls",
50            Self::Renderers => "renderers",
51            Self::RuntimeActions => "runtime_actions",
52        }
53    }
54}
55
56#[derive(Debug, Clone, PartialEq, Eq)]
57pub struct ExtensionBackendInfo {
58    pub name: &'static str,
59    pub api_version: u32,
60    pub capabilities: BTreeSet<ExtensionCapability>,
61}
62
63impl ExtensionBackendInfo {
64    pub fn new(name: &'static str) -> Self {
65        Self {
66            name,
67            api_version: EXTENSION_API_VERSION,
68            capabilities: BTreeSet::new(),
69        }
70    }
71
72    pub fn with_capabilities(
73        name: &'static str,
74        capabilities: impl IntoIterator<Item = ExtensionCapability>,
75    ) -> Self {
76        Self {
77            name,
78            api_version: EXTENSION_API_VERSION,
79            capabilities: capabilities.into_iter().collect(),
80        }
81    }
82
83    pub fn supports(&self, capability: ExtensionCapability) -> bool {
84        self.capabilities.contains(&capability)
85    }
86
87    pub fn capability_names(&self) -> Vec<&'static str> {
88        self.capabilities
89            .iter()
90            .map(|capability| capability.as_str())
91            .collect()
92    }
93}
94
95/// Common metadata contract implemented by every extension backend.
96pub trait ExtensionBackend {
97    fn backend_info(&self) -> ExtensionBackendInfo;
98}
99
100/// Capabilities currently provided by the Rust-native cdylib backend.
101pub fn native_backend_info() -> ExtensionBackendInfo {
102    ExtensionBackendInfo::with_capabilities(
103        "native-rust",
104        [
105            ExtensionCapability::Tools,
106            ExtensionCapability::Commands,
107            ExtensionCapability::Resources,
108            ExtensionCapability::Session,
109            ExtensionCapability::Models,
110            ExtensionCapability::Events,
111            ExtensionCapability::Providers,
112            ExtensionCapability::ProviderCalls,
113            ExtensionCapability::Renderers,
114            ExtensionCapability::RuntimeActions,
115        ],
116    )
117}
118
119impl ExtensionBackend for rpi_extensions::ExtensionSession {
120    fn backend_info(&self) -> ExtensionBackendInfo {
121        native_backend_info()
122    }
123}