Skip to main content

starweaver_context/
host_capabilities.rs

1//! Read-only access to host capability dependencies during execution.
2
3use std::{collections::BTreeSet, sync::Arc};
4
5use crate::DependencyStore;
6
7/// Host-authorized dependency grants for one Strict tool.
8#[derive(Clone, Debug, Default, Eq, PartialEq)]
9pub struct ToolCapabilityGrant {
10    /// Stable host capability names the tool may access.
11    pub host_capabilities: BTreeSet<String>,
12    /// Runtime-recognized mutable context capability names the tool may access.
13    pub context_capabilities: BTreeSet<String>,
14    /// Whether the tool may receive configured shell environment values.
15    pub shell_environment: bool,
16}
17
18impl ToolCapabilityGrant {
19    /// Create a deny-by-default grant.
20    #[must_use]
21    pub fn new() -> Self {
22        Self::default()
23    }
24
25    /// Authorize named host capabilities.
26    #[must_use]
27    pub fn with_host_capabilities(
28        mut self,
29        capabilities: impl IntoIterator<Item = impl Into<String>>,
30    ) -> Self {
31        self.host_capabilities = capabilities.into_iter().map(Into::into).collect();
32        self
33    }
34
35    /// Authorize mutable context capabilities.
36    #[must_use]
37    pub fn with_context_capabilities(
38        mut self,
39        capabilities: impl IntoIterator<Item = impl Into<String>>,
40    ) -> Self {
41        self.context_capabilities = capabilities.into_iter().map(Into::into).collect();
42        self
43    }
44
45    /// Authorize or deny shell environment projection.
46    #[must_use]
47    pub const fn with_shell_environment(mut self, allowed: bool) -> Self {
48        self.shell_environment = allowed;
49        self
50    }
51}
52
53/// Read-only host capability registry supplied to runtime hooks and tool calls.
54///
55/// This handle exposes explicitly attached typed capabilities without exposing
56/// conversation, task, note, usage, lifecycle, or other `AgentContext` state.
57#[derive(Clone, Default)]
58pub struct HostCapabilities {
59    dependencies: DependencyStore,
60}
61
62impl HostCapabilities {
63    pub(crate) const fn new(dependencies: DependencyStore) -> Self {
64        Self { dependencies }
65    }
66
67    /// Get a host capability by Rust type.
68    #[must_use]
69    pub fn get<T>(&self) -> Option<Arc<T>>
70    where
71        T: Send + Sync + 'static,
72    {
73        self.dependencies.get::<T>()
74    }
75
76    /// Get a named host capability.
77    #[must_use]
78    pub fn get_named<T>(&self, name: &str) -> Option<Arc<T>>
79    where
80        T: Send + Sync + 'static,
81    {
82        self.dependencies.get_named::<T>(name)
83    }
84
85    /// Return the stable dependency keys available through this handle.
86    #[must_use]
87    pub fn keys(&self) -> Vec<String> {
88        self.dependencies.keys()
89    }
90
91    /// Return whether no host capabilities are attached.
92    #[must_use]
93    pub fn is_empty(&self) -> bool {
94        self.dependencies.is_empty()
95    }
96}
97
98impl std::fmt::Debug for HostCapabilities {
99    fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
100        formatter
101            .debug_struct("HostCapabilities")
102            .field("keys", &self.keys())
103            .finish()
104    }
105}